1 /** Downloads managment
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/dialog.h"
28 #include "cache/cache.h"
29 #include "config/options.h"
30 #include "dialogs/document.h"
31 #include "dialogs/download.h"
32 #include "dialogs/menu.h"
33 #include "intl/gettext/libintl.h"
34 #include "main/object.h"
35 #include "main/select.h"
36 #include "mime/mime.h"
37 #include "network/connection.h"
38 #include "network/progress.h"
39 #include "network/state.h"
40 #include "osdep/osdep.h"
41 #include "protocol/bittorrent/dialogs.h"
42 #include "protocol/date.h"
43 #include "protocol/protocol.h"
44 #include "protocol/uri.h"
45 #include "session/download.h"
46 #include "session/history.h"
47 #include "session/location.h"
48 #include "session/session.h"
49 #include "session/task.h"
50 #include "terminal/draw.h"
51 #include "terminal/screen.h"
52 #include "terminal/terminal.h"
53 #include "util/conv.h"
54 #include "util/error.h"
55 #include "util/file.h"
56 #include "util/lists.h"
57 #include "util/memlist.h"
58 #include "util/memory.h"
59 #include "util/string.h"
60 #include "util/time.h"
63 /* TODO: tp_*() should be in separate file, I guess? --pasky */
66 INIT_LIST_OF(struct file_download
, downloads
);
69 download_is_progressing(struct download
*download
)
72 && is_in_state(download
->state
, S_TRANS
)
73 && has_progress(download
->progress
);
77 are_there_downloads(void)
79 struct file_download
*file_download
;
81 foreach (file_download
, downloads
)
82 if (!file_download
->external_handler
)
89 static void download_data(struct download
*download
, struct file_download
*file_download
);
91 /*! @note If this fails, the caller is responsible of freeing @a file
92 * and closing @a fd. */
93 struct file_download
*
94 init_file_download(struct uri
*uri
, struct session
*ses
, unsigned char *file
, int fd
)
96 struct file_download
*file_download
;
98 file_download
= mem_calloc(1, sizeof(*file_download
));
99 if (!file_download
) return NULL
;
101 /* Actually we could allow fragments in the URI and just change all the
102 * places that compares and shows the URI, but for now it is much
103 * easier this way. */
104 file_download
->uri
= get_composed_uri(uri
, URI_BASE
);
105 if (!file_download
->uri
) {
106 mem_free(file_download
);
110 init_download_display(file_download
);
112 file_download
->file
= file
;
113 file_download
->handle
= fd
;
115 file_download
->download
.callback
= (download_callback_T
*) download_data
;
116 file_download
->download
.data
= file_download
;
117 file_download
->ses
= ses
;
118 /* The tab may be closed, but we will still want to ie. open the
119 * handler on that terminal. */
120 file_download
->term
= ses
->tab
->term
;
122 object_nolock(file_download
, "file_download"); /* Debugging purpose. */
123 add_to_list(downloads
, file_download
);
125 return file_download
;
130 abort_download(struct file_download
*file_download
)
133 /* When hacking to cleanup the download code, remove lots of duplicated
134 * code and implement stuff from bug 435 we should reintroduce this
135 * assertion. Currently it will trigger often and shows that the
136 * download dialog code potentially could access free()d memory. */
137 assert(!is_object_used(file_download
));
139 done_download_display(file_download
);
141 if (file_download
->ses
)
142 check_questions_queue(file_download
->ses
);
144 if (file_download
->dlg_data
)
145 cancel_dialog(file_download
->dlg_data
, NULL
);
146 cancel_download(&file_download
->download
, file_download
->stop
);
147 if (file_download
->uri
) done_uri(file_download
->uri
);
149 if (file_download
->handle
!= -1) {
150 prealloc_truncate(file_download
->handle
, file_download
->seek
);
151 close(file_download
->handle
);
154 mem_free_if(file_download
->external_handler
);
155 if (file_download
->file
) {
156 if (file_download
->delete) unlink(file_download
->file
);
157 mem_free(file_download
->file
);
159 del_from_list(file_download
);
160 mem_free(file_download
);
165 kill_downloads_to_file(unsigned char *file
)
167 struct file_download
*file_download
;
169 foreach (file_download
, downloads
) {
170 if (strcmp(file_download
->file
, file
))
173 file_download
= file_download
->prev
;
174 abort_download(file_download
->next
);
180 abort_all_downloads(void)
182 while (!list_empty(downloads
))
183 abort_download(downloads
.next
);
188 destroy_downloads(struct session
*ses
)
190 struct file_download
*file_download
, *next
;
193 /* We are supposed to blat all downloads to external handlers belonging
194 * to @ses, but we will refuse to do so if there is another session
195 * bound to this terminal. That looks like the reasonable thing to do,
196 * fulfilling the principle of least astonishment. */
197 foreach (s
, sessions
) {
198 if (s
== ses
|| s
->tab
->term
!= ses
->tab
->term
)
201 foreach (file_download
, downloads
) {
202 if (file_download
->ses
!= ses
)
205 file_download
->ses
= s
;
211 foreachsafe (file_download
, next
, downloads
) {
212 if (file_download
->ses
!= ses
)
215 if (!file_download
->external_handler
) {
216 file_download
->ses
= NULL
;
220 abort_download(file_download
);
225 detach_downloads_from_terminal(struct terminal
*term
)
227 struct file_download
*file_download
, *next
;
229 assert(term
!= NULL
);
230 if_assert_failed
return;
232 foreachsafe (file_download
, next
, downloads
) {
233 if (file_download
->term
!= term
)
236 if (!file_download
->external_handler
) {
237 file_download
->term
= NULL
;
238 if (file_download
->ses
239 && file_download
->ses
->tab
->term
== term
)
240 file_download
->ses
= NULL
;
244 abort_download(file_download
);
249 download_error_dialog(struct file_download
*file_download
, int saved_errno
)
251 unsigned char *emsg
= (unsigned char *) strerror(saved_errno
);
252 struct session
*ses
= file_download
->ses
;
253 struct terminal
*term
= file_download
->term
;
257 info_box(term
, MSGBOX_FREE_TEXT
,
258 N_("Download error"), ALIGN_CENTER
,
259 msg_text(term
, N_("Could not create file '%s':\n%s"),
260 file_download
->file
, emsg
));
264 write_cache_entry_to_file(struct cache_entry
*cached
, struct file_download
*file_download
)
266 struct fragment
*frag
;
268 if (file_download
->download
.progress
&& file_download
->download
.progress
->seek
) {
269 file_download
->seek
= file_download
->download
.progress
->seek
;
270 file_download
->download
.progress
->seek
= 0;
271 /* This is exclusive with the prealloc, thus we can perform
272 * this in front of that thing safely. */
273 if (lseek(file_download
->handle
, file_download
->seek
, SEEK_SET
) < 0) {
274 download_error_dialog(file_download
, errno
);
279 foreach (frag
, cached
->frag
) {
280 off_t remain
= file_download
->seek
- frag
->offset
;
281 int *h
= &file_download
->handle
;
284 if (remain
< 0 || frag
->length
<= remain
)
287 #ifdef USE_OPEN_PREALLOC
288 if (!file_download
->seek
289 && (!file_download
->download
.progress
290 || file_download
->download
.progress
->size
> 0)) {
292 *h
= open_prealloc(file_download
->file
,
293 O_CREAT
|O_WRONLY
|O_TRUNC
,
295 file_download
->download
.progress
296 ? file_download
->download
.progress
->size
299 download_error_dialog(file_download
, errno
);
306 w
= safe_write(*h
, frag
->data
+ remain
, frag
->length
- remain
);
308 download_error_dialog(file_download
, errno
);
312 file_download
->seek
+= w
;
319 abort_download_and_beep(struct file_download
*file_download
, struct terminal
*term
)
321 if (term
&& get_opt_int("document.download.notify_bell",
323 + file_download
->notify
>= 2) {
327 abort_download(file_download
);
330 struct exec_mailcap
{
332 unsigned char *command
;
337 do_follow_url_mailcap(struct session
*ses
, struct uri
*uri
)
340 print_error_dialog(ses
, connection_state(S_BAD_URL
), uri
, PRI_CANCEL
);
344 ses
->reloadlevel
= CACHE_MODE_NORMAL
;
346 if (ses
->task
.type
== TASK_FORWARD
) {
347 if (compare_uri(ses
->loading_uri
, uri
, 0)) {
348 /* We're already loading the URL. */
353 abort_loading(ses
, 0);
355 ses_goto(ses
, uri
, NULL
, NULL
, CACHE_MODE_NORMAL
, TASK_FORWARD
, 0);
360 exec_mailcap_command(void *data
)
362 struct exec_mailcap
*exec_mailcap
= data
;
365 if (exec_mailcap
->command
) {
366 int length
= strlen(exec_mailcap
->command
)
367 + sizeof("mailcap:");
368 unsigned char *buf
= malloc(length
);
371 struct uri
*ref
= get_uri("mailcap:elmailcap", 0);
373 struct session
*ses
= exec_mailcap
->ses
;
375 memcpy(buf
, "mailcap:", 8);
376 memcpy(buf
+ 8, exec_mailcap
->command
, length
- 9);
377 buf
[length
- 1] = '\0';
379 uri
= get_uri(buf
, 0);
381 set_session_referrer(ses
, ref
);
382 if (ref
) done_uri(ref
);
384 do_follow_url_mailcap(ses
, uri
);
385 if (uri
) done_uri(uri
);
387 mem_free(exec_mailcap
->command
);
389 mem_free_if(exec_mailcap
->file
);
390 mem_free(exec_mailcap
);
395 exec_later(struct session
*ses
, unsigned char *handler
, unsigned char *file
)
397 struct exec_mailcap
*exec_mailcap
= calloc(1, sizeof(*exec_mailcap
));
400 exec_mailcap
->ses
= ses
;
401 exec_mailcap
->command
= null_or_stracpy(handler
);
402 exec_mailcap
->file
= null_or_stracpy(file
);
403 register_bottom_half(exec_mailcap_command
, exec_mailcap
);
408 download_data_store(struct download
*download
, struct file_download
*file_download
)
410 struct terminal
*term
= file_download
->term
;
412 assert_terminal_ptr_not_dangling(term
);
413 if_assert_failed term
= file_download
->term
= NULL
;
415 if (is_in_progress_state(download
->state
)) {
416 if (file_download
->dlg_data
)
417 redraw_dialog(file_download
->dlg_data
, 1);
421 /* If the original terminal of the download has been closed,
422 * display any messages in the default terminal instead. */
424 term
= get_default_terminal(); /* may be NULL too */
426 if (!is_in_state(download
->state
, S_OK
)) {
427 unsigned char *url
= get_uri_string(file_download
->uri
, URI_PUBLIC
);
428 struct connection_state state
= download
->state
;
430 /* abort_download_and_beep allows term==NULL. */
431 abort_download_and_beep(file_download
, term
);
436 info_box(term
, MSGBOX_FREE_TEXT
,
437 N_("Download error"), ALIGN_CENTER
,
438 msg_text(term
, N_("Error downloading %s:\n\n%s"),
439 url
, get_state_message(state
, term
)));
445 if (file_download
->external_handler
) {
447 /* There is no terminal in which to run the handler.
448 * Abort the download. file_download->delete should
449 * be 1 here so that the following call also deletes
450 * the temporary file. */
451 abort_download(file_download
);
455 prealloc_truncate(file_download
->handle
, file_download
->seek
);
456 close(file_download
->handle
);
457 file_download
->handle
= -1;
458 if (file_download
->copiousoutput
) {
459 exec_later(file_download
->ses
,
460 file_download
->external_handler
, NULL
);
462 exec_on_terminal(term
, file_download
->external_handler
,
464 file_download
->block
? TERM_EXEC_FG
:
467 file_download
->delete = 0;
468 abort_download_and_beep(file_download
, term
);
472 if (file_download
->notify
&& term
) {
473 unsigned char *url
= get_uri_string(file_download
->uri
, URI_PUBLIC
);
475 /* This is apparently a little racy. Deleting the box item will
476 * update the download browser _after_ the notification dialog
477 * has been drawn whereby it will be hidden. This should make
478 * the download browser update before launcing any
480 done_download_display(file_download
);
483 info_box(term
, MSGBOX_FREE_TEXT
,
484 N_("Download"), ALIGN_CENTER
,
485 msg_text(term
, N_("Download complete:\n%s"), url
));
490 if (file_download
->remotetime
491 && get_opt_bool("document.download.set_original_time",
492 file_download
->ses
)) {
495 foo
.actime
= foo
.modtime
= file_download
->remotetime
;
496 utime(file_download
->file
, &foo
);
499 /* abort_download_and_beep allows term==NULL. */
500 abort_download_and_beep(file_download
, term
);
504 download_data(struct download
*download
, struct file_download
*file_download
)
506 struct cache_entry
*cached
= download
->cached
;
508 if (!cached
|| is_in_queued_state(download
->state
)) {
509 download_data_store(download
, file_download
);
513 if (cached
->last_modified
)
514 file_download
->remotetime
= parse_date(&cached
->last_modified
, NULL
, 0, 1);
516 if (cached
->redirect
&& file_download
->redirect_cnt
++ < MAX_REDIRECTS
) {
517 cancel_download(&file_download
->download
, 0);
519 assertm(compare_uri(cached
->uri
, file_download
->uri
, 0),
520 "Redirecting using bad base URI");
522 done_uri(file_download
->uri
);
524 file_download
->uri
= get_uri_reference(cached
->redirect
);
525 file_download
->download
.state
= connection_state(S_WAIT_REDIR
);
527 if (file_download
->dlg_data
)
528 redraw_dialog(file_download
->dlg_data
, 1);
530 load_uri(file_download
->uri
, cached
->uri
, &file_download
->download
,
531 PRI_DOWNLOAD
, CACHE_MODE_NORMAL
,
532 download
->progress
? download
->progress
->start
: 0);
537 if (!write_cache_entry_to_file(cached
, file_download
)) {
538 detach_connection(download
, file_download
->seek
);
539 abort_download(file_download
);
543 detach_connection(download
, file_download
->seek
);
544 download_data_store(download
, file_download
);
547 /** Type of the callback function that will be called when the user
548 * answers the question posed by lookup_unique_name().
551 * The terminal on which the callback should display any windows.
552 * Comes directly from the @a term argument of lookup_unique_name().
555 * The name of the local file to which the data should be downloaded,
556 * or NULL if the download should not begin. The callback is
557 * responsible of doing mem_free(@a file).
560 * A pointer to any data that the callback cares about.
561 * Comes directly from the @a data argument of lookup_unique_name().
564 * The same as the @a flags argument of create_download_file(),
565 * except the ::DOWNLOAD_RESUME_SELECTED bit will be changed to match
566 * what the user chose.
568 * @relates lun_hop */
569 typedef void lun_callback_T(struct terminal
*term
, unsigned char *file
,
570 void *data
, enum download_flags flags
);
572 /** The user is being asked what to do when the local file for
573 * the download already exists. This structure is allocated by
574 * lookup_unique_name() and freed by each lun_* function:
575 * lun_alternate(), lun_cancel(), lun_overwrite(), and lun_resume(). */
577 /** The terminal in which ELinks is asking the question.
578 * This gets passed to #callback. */
579 struct terminal
*term
;
581 /** The name of the local file into which the data was
582 * originally going to be downloaded, but which already
583 * exists. In this string, "~" has already been expanded
584 * to the home directory. The string must be freed with
586 unsigned char *ofile
;
588 /** An alternative file name that the user may choose instead
589 * of #ofile. The string must be freed with mem_free(). */
592 /** This function will be called when the user answers. */
593 lun_callback_T
*callback
;
595 /** A pointer to be passed to #callback. */
598 /** Saved flags to be passed to #callback.
599 * If the user chooses to resume, then lun_resume() sets
600 * ::DOWNLOAD_RESUME_SELECTED when it calls #callback.
602 * @invariant The ::DOWNLOAD_RESUME_SELECTED bit should be
603 * clear here because otherwise there would have been no
604 * reason to ask the user and initialize this structure. */
605 enum download_flags flags
;
608 /** Data saved by common_download() for the common_download_do()
613 /** The URI from which the data will be downloaded. */
614 struct uri
*download_uri
;
616 /** The name of the local file to which the data will be
617 * downloaded. This is initially NULL, but its address is
618 * given to create_download_file(), which arranges for the
619 * pointer to be set before common_download_do() is called.
620 * The string must be freed with mem_free(). */
621 unsigned char *real_file
;
624 /** Data saved by continue_download() for the continue_download_do()
627 struct type_query
*type_query
;
629 /** The name of the local file to which the data will be
630 * downloaded. This is initially NULL, but its address is
631 * given to create_download_file(), which arranges for the
632 * pointer to be set before continue_download_do() is called.
633 * The string must be freed with mem_free(). */
634 unsigned char *real_file
;
639 /** Data saved by create_download_file() for the create_download_file_do()
642 /** Where to save the name of the file that was actually
643 * opened. One of the arguments of #callback is a file
644 * descriptor for this file. @c real_file can be NULL if
645 * #callback does not care about the name. */
646 unsigned char **real_file
;
648 /** This function will be called when the file has been opened,
649 * or when it is known that the file will not be opened. */
650 cdf_callback_T
*callback
;
652 /** A pointer to be passed to #callback. */
656 /** The use chose "Save under the alternative name" when asked where
657 * to download a file.
659 * lookup_unique_name() passes this function as a ::done_handler_T to
662 * @relates lun_hop */
664 lun_alternate(void *lun_hop_
)
666 struct lun_hop
*lun_hop
= lun_hop_
;
668 lun_hop
->callback(lun_hop
->term
, lun_hop
->file
, lun_hop
->data
,
670 mem_free_if(lun_hop
->ofile
);
674 /** The use chose "Cancel" when asked where to download a file.
676 * lookup_unique_name() passes this function as a ::done_handler_T to
679 * @relates lun_hop */
681 lun_cancel(void *lun_hop_
)
683 struct lun_hop
*lun_hop
= lun_hop_
;
685 lun_hop
->callback(lun_hop
->term
, NULL
, lun_hop
->data
,
687 mem_free_if(lun_hop
->ofile
);
688 mem_free_if(lun_hop
->file
);
692 /** The use chose "Overwrite the original file" when asked where to
695 * lookup_unique_name() passes this function as a ::done_handler_T to
698 * @relates lun_hop */
700 lun_overwrite(void *lun_hop_
)
702 struct lun_hop
*lun_hop
= lun_hop_
;
704 lun_hop
->callback(lun_hop
->term
, lun_hop
->ofile
, lun_hop
->data
,
706 mem_free_if(lun_hop
->file
);
710 /** The user chose "Resume download of the original file" when asked
711 * where to download a file.
713 * lookup_unique_name() passes this function as a ::done_handler_T to
716 * @relates lun_hop */
718 lun_resume(void *lun_hop_
)
720 struct lun_hop
*lun_hop
= lun_hop_
;
722 lun_hop
->callback(lun_hop
->term
, lun_hop
->ofile
, lun_hop
->data
,
723 lun_hop
->flags
| DOWNLOAD_RESUME_SELECTED
);
724 mem_free_if(lun_hop
->file
);
729 /** If attempting to download to an existing file, perhaps ask
730 * the user whether to resume, overwrite, or save elsewhere.
731 * This function constructs a struct lun_hop, which will be freed
732 * when the user answers the question.
735 * The terminal in which this function should show its UI.
738 * A proposed name for the local file to which the data would be
739 * downloaded. "~" here refers to the home directory.
740 * lookup_unique_name() treats this original string as read-only.
743 * Flags controlling how to download the file.
744 * ::DOWNLOAD_RESUME_ALLOWED adds a "Resume" button to the dialog.
745 * ::DOWNLOAD_RESUME_SELECTED means the user already chose to resume
746 * downloading (with ::ACT_MAIN_LINK_DOWNLOAD_RESUME), before ELinks
747 * even asked for the file name; thus don't ask whether to overwrite.
748 * Other flags, such as ::DOWNLOAD_EXTERNAL, have no effect at this
749 * level but they get passed to @a callback.
752 * Will be called when the user answers, or right away if the question
753 * need not or cannot be asked.
756 * A pointer to be passed to @a callback.
758 * @relates lun_hop */
760 lookup_unique_name(struct terminal
*term
, unsigned char *ofile
,
761 enum download_flags flags
,
762 lun_callback_T
*callback
, void *data
)
764 /* [gettext_accelerator_context(.lookup_unique_name)] */
765 struct lun_hop
*lun_hop
= NULL
;
766 unsigned char *file
= NULL
;
767 struct dialog_data
*dialog_data
;
770 ofile
= expand_tilde(ofile
);
771 if (!ofile
) goto error
;
773 /* Minor code duplication to prevent useless call to get_opt_int()
774 * if possible. --Zas */
775 if (flags
& DOWNLOAD_RESUME_SELECTED
) {
776 callback(term
, ofile
, data
, flags
);
780 /* !overwrite means always silently overwrite, which may be admitelly
781 * indeed a little confusing ;-) */
782 overwrite
= get_opt_int("document.download.overwrite", NULL
);
784 /* Nothing special to do... */
785 callback(term
, ofile
, data
, flags
);
789 /* Check if file is a directory, and use a default name if it's the
791 if (file_is_dir(ofile
)) {
792 info_box(term
, MSGBOX_FREE_TEXT
,
793 N_("Download error"), ALIGN_CENTER
,
794 msg_text(term
, N_("'%s' is a directory."),
799 /* Check if the file already exists (file != ofile). */
800 file
= get_unique_name(ofile
);
802 if (!file
|| overwrite
== 1 || file
== ofile
) {
803 /* Still nothing special to do... */
804 if (file
!= ofile
) mem_free(ofile
);
805 callback(term
, file
, data
, flags
& ~DOWNLOAD_RESUME_SELECTED
);
809 /* overwrite == 2 (ask) and file != ofile (=> original file already
812 lun_hop
= mem_calloc(1, sizeof(*lun_hop
));
813 if (!lun_hop
) goto error
;
814 lun_hop
->term
= term
;
815 lun_hop
->ofile
= ofile
;
816 lun_hop
->file
= file
; /* file != ofile verified above */
817 lun_hop
->callback
= callback
;
818 lun_hop
->data
= data
;
819 lun_hop
->flags
= flags
;
821 dialog_data
= msg_box(
822 term
, NULL
, MSGBOX_FREE_TEXT
,
823 N_("File exists"), ALIGN_CENTER
,
824 msg_text(term
, N_("This file already exists:\n"
826 "The alternative filename is:\n"
828 empty_string_or_(lun_hop
->ofile
),
829 empty_string_or_(file
)),
831 MSG_BOX_BUTTON(N_("Sa~ve under the alternative name"), lun_alternate
, B_ENTER
),
832 MSG_BOX_BUTTON(N_("~Overwrite the original file"), lun_overwrite
, 0),
833 MSG_BOX_BUTTON((flags
& DOWNLOAD_RESUME_ALLOWED
834 ? N_("~Resume download of the original file")
837 MSG_BOX_BUTTON(N_("~Cancel"), lun_cancel
, B_ESC
));
838 if (!dialog_data
) goto error
;
842 mem_free_if(lun_hop
);
843 if (file
!= ofile
) mem_free_if(file
);
845 callback(term
, NULL
, data
, flags
& ~DOWNLOAD_RESUME_SELECTED
);
850 /** Now that the final name of the download file has been chosen,
851 * open the file and call the ::cdf_callback_T that was originally
852 * given to create_download_file().
854 * create_download_file() passes this function as a ::lun_callback_T
855 * to lookup_unique_name().
857 * @relates cdf_hop */
859 create_download_file_do(struct terminal
*term
, unsigned char *file
,
860 void *data
, enum download_flags flags
)
862 struct cdf_hop
*cdf_hop
= data
;
866 #ifdef NO_FILE_SECURITY
869 int sf
= !!(flags
& DOWNLOAD_EXTERNAL
);
872 if (!file
) goto finish
;
877 /* Create parent directories if needed. */
880 /* O_APPEND means repositioning at the end of file before each write(),
881 * thus ignoring seek()s and that can hide mysterious bugs. IMHO.
883 h
= open(file
, O_CREAT
| O_WRONLY
884 | (flags
& DOWNLOAD_RESUME_SELECTED
? 0 : O_TRUNC
)
885 | (sf
&& !(flags
& DOWNLOAD_RESUME_SELECTED
) ? O_EXCL
: 0),
887 saved_errno
= errno
; /* Saved in case of ... --Zas */
895 info_box(term
, MSGBOX_FREE_TEXT
,
896 N_("Download error"), ALIGN_CENTER
,
897 msg_text(term
, N_("Could not create file '%s':\n%s"),
898 file
, strerror(saved_errno
)));
906 if (!(flags
& DOWNLOAD_EXTERNAL
)) {
907 unsigned char *download_dir
= get_opt_str("document.download.directory", NULL
);
910 safe_strncpy(download_dir
, file
, MAX_STR_LEN
);
912 /* Find the used directory so it's available in history */
913 for (i
= strlen(download_dir
); i
>= 0; i
--)
914 if (dir_sep(download_dir
[i
]))
916 download_dir
[i
+ 1] = 0;
920 if (cdf_hop
->real_file
)
921 *cdf_hop
->real_file
= file
;
926 cdf_hop
->callback(term
, h
, cdf_hop
->data
, flags
);
930 /** Create a file to which data can be downloaded.
931 * This function constructs a struct cdf_hop that will be freed
932 * when @a callback returns.
935 * If any dialog boxes are needed, show them in this terminal.
938 * A proposed name for the local file to which the data would be
939 * downloaded. "~" here refers to the home directory.
940 * create_download_file() treats this original string as read-only.
943 * If non-NULL, prepare to save in *@a real_file the name of the local
944 * file that was eventually opened. @a callback must then arrange for
945 * this string to be freed with mem_free().
948 * Flags controlling how to download the file.
949 * ::DOWNLOAD_RESUME_ALLOWED adds a "Resume" button to the dialog.
950 * ::DOWNLOAD_RESUME_SELECTED skips the dialog entirely.
951 * ::DOWNLOAD_EXTERNAL causes the file to be created with settings
952 * suitable for a temporary file: give only the user herself access to
953 * the file (even if the umask is looser), and create the file with
954 * @c O_EXCL unless resuming.
957 * This function will be called when the file has been opened,
958 * or when it is known that the file will not be opened.
961 * A pointer to be passed to @a callback.
963 * @relates cdf_hop */
965 create_download_file(struct terminal
*term
, unsigned char *fi
,
966 unsigned char **real_file
,
967 enum download_flags flags
,
968 cdf_callback_T
*callback
, void *data
)
970 struct cdf_hop
*cdf_hop
= mem_calloc(1, sizeof(*cdf_hop
));
974 callback(term
, -1, data
, flags
& ~DOWNLOAD_RESUME_SELECTED
);
978 cdf_hop
->real_file
= real_file
;
979 cdf_hop
->callback
= callback
;
980 cdf_hop
->data
= data
;
982 /* FIXME: The wd bussiness is probably useless here? --pasky */
986 /* Also the tilde will be expanded here. */
987 lookup_unique_name(term
, fi
, flags
, create_download_file_do
, cdf_hop
);
996 static unsigned char *
997 get_temp_name(struct uri
*uri
)
1000 unsigned char *extension
;
1002 * We use tempnam() here, which is unsafe (race condition), for now.
1003 * This should be changed at some time, but it needs an in-depth work
1004 * of whole download code. --Zas */
1005 unsigned char *nm
= tempnam(NULL
, ELINKS_TEMPNAME_PREFIX
);
1007 if (!nm
) return NULL
;
1009 if (!init_string(&name
)) {
1014 add_to_string(&name
, nm
);
1017 extension
= get_extension_from_uri(uri
);
1019 add_shell_safe_to_string(&name
, extension
, strlen(extension
));
1020 mem_free(extension
);
1027 static unsigned char *
1028 subst_file(unsigned char *prog
, unsigned char *file
)
1031 /* When there is no %s in the mailcap entry, the handler program reads
1032 * data from stdin instead of a file. */
1035 if (!init_string(&name
)) return NULL
;
1040 for (p
= 0; prog
[p
] && prog
[p
] != '%'; p
++);
1042 add_bytes_to_string(&name
, prog
, p
);
1047 #if defined(HAVE_CYGWIN_CONV_TO_FULL_WIN32_PATH)
1049 unsigned char new_path
[MAX_PATH
];
1051 unsigned char new_path
[1024];
1054 cygwin_conv_to_full_win32_path(file
, new_path
);
1055 add_to_string(&name
, new_path
);
1057 add_shell_quoted_to_string(&name
, file
, strlen(file
));
1066 if (init_string(&s
)) {
1067 add_to_string(&s
, "/bin/cat ");
1068 add_shell_quoted_to_string(&s
, file
, strlen(file
));
1069 add_to_string(&s
, " | ");
1070 add_string_to_string(&s
, &name
);
1080 /*! common_download() passes this function as a ::cdf_callback_T to
1081 * create_download_file().
1083 * @relates cmdw_hop */
1085 common_download_do(struct terminal
*term
, int fd
, void *data
,
1086 enum download_flags flags
)
1088 struct file_download
*file_download
;
1089 struct cmdw_hop
*cmdw_hop
= data
;
1090 struct uri
*download_uri
= cmdw_hop
->download_uri
;
1091 unsigned char *file
= cmdw_hop
->real_file
;
1092 struct session
*ses
= cmdw_hop
->ses
;
1097 if (!file
|| fstat(fd
, &buf
)) goto finish
;
1099 file_download
= init_file_download(download_uri
, ses
, file
, fd
);
1100 if (!file_download
) goto finish
;
1101 /* If init_file_download succeeds, it takes ownership of file
1106 if (flags
& DOWNLOAD_RESUME_SELECTED
)
1107 file_download
->seek
= buf
.st_size
;
1109 display_download(ses
->tab
->term
, file_download
, ses
);
1111 load_uri(file_download
->uri
, ses
->referrer
, &file_download
->download
,
1112 PRI_DOWNLOAD
, CACHE_MODE_NORMAL
, file_download
->seek
);
1116 if (fd
!= -1) close(fd
);
1117 done_uri(download_uri
);
1120 /** Begin or resume downloading from session.download_uri to the
1121 * @a file specified by the user.
1123 * This function contains the code shared between start_download() and
1124 * resume_download().
1126 * @relates cmdw_hop */
1128 common_download(struct session
*ses
, unsigned char *file
,
1129 enum download_flags flags
)
1131 struct cmdw_hop
*cmdw_hop
;
1133 if (!ses
->download_uri
) return;
1135 cmdw_hop
= mem_calloc(1, sizeof(*cmdw_hop
));
1136 if (!cmdw_hop
) return;
1137 cmdw_hop
->ses
= ses
;
1138 cmdw_hop
->download_uri
= ses
->download_uri
;
1139 ses
->download_uri
= NULL
;
1141 kill_downloads_to_file(file
);
1143 create_download_file(ses
->tab
->term
, file
, &cmdw_hop
->real_file
,
1144 flags
, common_download_do
, cmdw_hop
);
1147 /** Begin downloading from session.download_uri to the @a file
1148 * specified by the user.
1150 * The ::ACT_MAIN_SAVE_AS, ::ACT_MAIN_SAVE_URL_AS,
1151 * ::ACT_MAIN_LINK_DOWNLOAD, and ::ACT_MAIN_LINK_DOWNLOAD_IMAGE
1152 * actions pass this function as the @c std callback to query_file().
1154 * @relates cmdw_hop */
1156 start_download(void *ses
, unsigned char *file
)
1158 common_download(ses
, file
,
1159 DOWNLOAD_RESUME_ALLOWED
);
1163 /** Resume downloading from session.download_uri to the @a file
1164 * specified by the user.
1166 * The ::ACT_MAIN_LINK_DOWNLOAD_RESUME action passes this function as
1167 * the @c std callback to query_file().
1169 * @relates cmdw_hop */
1171 resume_download(void *ses
, unsigned char *file
)
1173 common_download(ses
, file
,
1174 DOWNLOAD_RESUME_ALLOWED
| DOWNLOAD_RESUME_SELECTED
);
1177 /** Resume downloading a file, based on information in struct
1178 * codw_hop. This function actually starts a new download from the
1179 * current end of the file, even though a download from the beginning
1180 * is already in progress at codw_hop->type_query->download. The
1181 * caller will cancel the preexisting download after this function
1184 * @relates codw_hop */
1186 transform_codw_to_cmdw(struct terminal
*term
, int fd
,
1187 struct codw_hop
*codw_hop
,
1188 enum download_flags flags
)
1190 struct type_query
*type_query
= codw_hop
->type_query
;
1191 struct cmdw_hop
*cmdw_hop
= mem_calloc(1, sizeof(*cmdw_hop
));
1198 cmdw_hop
->ses
= type_query
->ses
;
1199 cmdw_hop
->download_uri
= get_uri_reference(type_query
->uri
);
1200 cmdw_hop
->real_file
= codw_hop
->real_file
;
1201 codw_hop
->real_file
= NULL
;
1203 common_download_do(term
, fd
, cmdw_hop
, flags
);
1206 /*! continue_download() passes this function as a ::cdf_callback_T to
1207 * create_download_file().
1209 * @relates codw_hop */
1211 continue_download_do(struct terminal
*term
, int fd
, void *data
,
1212 enum download_flags flags
)
1214 struct codw_hop
*codw_hop
= data
;
1215 struct file_download
*file_download
= NULL
;
1216 struct type_query
*type_query
;
1219 assert(codw_hop
->type_query
);
1220 assert(codw_hop
->type_query
->uri
);
1221 assert(codw_hop
->type_query
->ses
);
1223 type_query
= codw_hop
->type_query
;
1224 if (!codw_hop
->real_file
) goto cancel
;
1226 if (flags
& DOWNLOAD_RESUME_SELECTED
) {
1227 transform_codw_to_cmdw(term
, fd
, codw_hop
, flags
);
1228 fd
= -1; /* ownership transfer */
1232 file_download
= init_file_download(type_query
->uri
, type_query
->ses
,
1233 codw_hop
->real_file
, fd
);
1234 if (!file_download
) goto cancel
;
1235 /* If init_file_download succeeds, it takes ownership of
1236 * codw_hop->real_file and fd. */
1237 codw_hop
->real_file
= NULL
;
1240 if (type_query
->external_handler
) {
1241 file_download
->external_handler
= subst_file(type_query
->external_handler
,
1243 file_download
->delete = 1;
1244 file_download
->copiousoutput
= type_query
->copiousoutput
;
1245 mem_free(codw_hop
->file
);
1246 mem_free_set(&type_query
->external_handler
, NULL
);
1249 file_download
->block
= !!type_query
->block
;
1251 /* Done here and not in init_file_download() so that the external
1252 * handler can become initialized. */
1253 display_download(term
, file_download
, type_query
->ses
);
1255 move_download(&type_query
->download
, &file_download
->download
, PRI_DOWNLOAD
);
1256 done_type_query(type_query
);
1262 mem_free_if(codw_hop
->real_file
);
1263 if (fd
!= -1) close(fd
);
1264 if (type_query
->external_handler
) mem_free_if(codw_hop
->file
);
1265 tp_cancel(type_query
);
1269 /** When asked what to do with a file, the user chose to download it
1270 * to a local file named @a file.
1271 * Or an external handler was selected, in which case
1272 * type_query.external_handler is non-NULL and @a file does not
1273 * matter because this function will generate a name.
1275 * tp_save() passes this function as the @c std callback to query_file().
1277 * @relates codw_hop */
1279 continue_download(void *data
, unsigned char *file
)
1281 struct type_query
*type_query
= data
;
1282 struct codw_hop
*codw_hop
= mem_calloc(1, sizeof(*codw_hop
));
1285 tp_cancel(type_query
);
1289 if (type_query
->external_handler
) {
1290 /* FIXME: get_temp_name() calls tempnam(). --Zas */
1291 file
= get_temp_name(type_query
->uri
);
1294 tp_cancel(type_query
);
1299 codw_hop
->type_query
= type_query
;
1300 codw_hop
->file
= file
;
1302 kill_downloads_to_file(file
);
1304 create_download_file(type_query
->ses
->tab
->term
, file
,
1305 &codw_hop
->real_file
,
1306 type_query
->external_handler
1307 ? DOWNLOAD_RESUME_ALLOWED
| DOWNLOAD_EXTERNAL
1308 : DOWNLOAD_RESUME_ALLOWED
,
1309 continue_download_do
, codw_hop
);
1313 /*! @relates type_query */
1314 static struct type_query
*
1315 find_type_query(struct session
*ses
)
1317 struct type_query
*type_query
;
1319 foreach (type_query
, ses
->type_queries
)
1320 if (compare_uri(type_query
->uri
, ses
->loading_uri
, 0))
1326 /** Prepare to ask the user what to do with a file, but don't display
1327 * the window yet. To display it, do_type_query() must be called
1328 * separately. setup_download_handler() takes care of that.
1330 * @relates type_query */
1331 static struct type_query
*
1332 init_type_query(struct session
*ses
, struct download
*download
,
1333 struct cache_entry
*cached
)
1335 struct type_query
*type_query
;
1337 type_query
= mem_calloc(1, sizeof(*type_query
));
1338 if (!type_query
) return NULL
;
1340 type_query
->uri
= get_uri_reference(ses
->loading_uri
);
1341 type_query
->ses
= ses
;
1342 type_query
->target_frame
= null_or_stracpy(ses
->task
.target
.frame
);
1344 type_query
->cached
= cached
;
1345 type_query
->cgi
= cached
->cgi
;
1346 object_lock(type_query
->cached
);
1348 move_download(download
, &type_query
->download
, PRI_MAIN
);
1349 download
->state
= connection_state(S_OK
);
1351 add_to_list(ses
->type_queries
, type_query
);
1356 /** Cancel any download started for @a type_query, remove the structure
1357 * from the session.type_queries list, and free it.
1359 * @relates type_query */
1361 done_type_query(struct type_query
*type_query
)
1363 /* Unregister any active download */
1364 cancel_download(&type_query
->download
, 0);
1366 object_unlock(type_query
->cached
);
1367 done_uri(type_query
->uri
);
1368 mem_free_if(type_query
->external_handler
);
1369 mem_free_if(type_query
->target_frame
);
1370 del_from_list(type_query
);
1371 mem_free(type_query
);
1375 /** The user chose "Cancel" when asked what to do with a file,
1376 * or the type query was cancelled for some other reason.
1378 * do_type_query() and bittorrent_query_callback() pass this function
1379 * as a ::done_handler_T to add_dlg_ok_button(), and tp_save() passes
1380 * this function as a @c cancel callback to query_file().
1382 * @relates type_query */
1384 tp_cancel(void *data
)
1386 struct type_query
*type_query
= data
;
1388 /* XXX: Should we really abort? (1 vs 0 as the last param) --pasky */
1389 cancel_download(&type_query
->download
, 1);
1390 done_type_query(type_query
);
1394 /** The user chose "Save" when asked what to do with a file.
1395 * Now ask her where to save the file.
1397 * do_type_query() and bittorrent_query_callback() pass this function
1398 * as a ::done_handler_T to add_dlg_ok_button().
1400 * @relates type_query */
1402 tp_save(struct type_query
*type_query
)
1404 mem_free_set(&type_query
->external_handler
, NULL
);
1405 query_file(type_query
->ses
, type_query
->uri
, type_query
, continue_download
, tp_cancel
, 1);
1408 /** The user chose "Show header" when asked what to do with a file.
1410 * do_type_query() passes this function as a ::widget_handler_T to
1411 * add_dlg_button(). Unlike with add_dlg_ok_button(), pressing this
1412 * button does not close the dialog box. This way, the user can
1413 * first examine the header and then choose what to do.
1415 * @relates type_query */
1416 static widget_handler_status_T
1417 tp_show_header(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
1419 struct type_query
*type_query
= widget_data
->widget
->data
;
1421 cached_header_dialog(type_query
->ses
, type_query
->cached
);
1423 return EVENT_PROCESSED
;
1427 /** The user chose "Display" when asked what to do with a file,
1428 * or she chose "Open" and there is no external handler.
1430 * do_type_query() and bittorrent_query_callback() pass this function
1431 * as a ::done_handler_T to add_dlg_ok_button().
1433 * @bug FIXME: We need to modify this function to take frame data
1434 * instead, as we want to use this function for frames as well (now,
1435 * when frame has content type text/plain, it is ignored and displayed
1438 * @relates type_query */
1440 tp_display(struct type_query
*type_query
)
1442 struct view_state
*vs
;
1443 struct session
*ses
= type_query
->ses
;
1444 struct uri
*loading_uri
= ses
->loading_uri
;
1445 unsigned char *target_frame
= null_or_stracpy(ses
->task
.target
.frame
);
1447 ses
->loading_uri
= type_query
->uri
;
1448 mem_free_set(&ses
->task
.target
.frame
, null_or_stracpy(type_query
->target_frame
));
1449 vs
= ses_forward(ses
, /* type_query->frame */ 0);
1450 if (vs
) vs
->plain
= 1;
1451 ses
->loading_uri
= loading_uri
;
1452 mem_free_set(&ses
->task
.target
.frame
, target_frame
);
1454 if (/* !type_query->frame */ 1) {
1455 struct download
*old
= &type_query
->download
;
1456 struct download
*new = &cur_loc(ses
)->download
;
1458 new->callback
= (download_callback_T
*) doc_loading_callback
;
1461 move_download(old
, new, PRI_MAIN
);
1465 done_type_query(type_query
);
1468 /** The user chose "Open" when asked what to do with a file.
1469 * Or an external handler was found and it has been configured
1470 * to run without asking.
1472 * do_type_query() passes this function as a ::done_handler_T to
1473 * add_dlg_ok_button().
1475 * @relates type_query */
1477 tp_open(struct type_query
*type_query
)
1479 if (!type_query
->external_handler
|| !*type_query
->external_handler
) {
1480 tp_display(type_query
);
1484 if (type_query
->uri
->protocol
== PROTOCOL_FILE
&& !type_query
->cgi
) {
1485 unsigned char *file
= get_uri_string(type_query
->uri
, URI_PATH
);
1486 unsigned char *handler
= NULL
;
1490 handler
= subst_file(type_query
->external_handler
, file
);
1495 if (type_query
->copiousoutput
) {
1496 exec_later(type_query
->ses
, handler
, NULL
);
1498 exec_on_terminal(type_query
->ses
->tab
->term
,
1499 handler
, "", type_query
->block
?
1500 TERM_EXEC_FG
: TERM_EXEC_BG
);
1505 done_type_query(type_query
);
1509 continue_download(type_query
, "");
1513 /*! Ask the user what to do with a file.
1515 * This function does not support BitTorrent downloads.
1516 * For those, query_bittorrent_dialog() must be called instead.
1517 * setup_download_handler() takes care of this.
1519 * @relates type_query */
1521 do_type_query(struct type_query
*type_query
, unsigned char *ct
, struct mime_handler
*handler
)
1523 /* [gettext_accelerator_context(.do_type_query)] */
1524 struct string filename
;
1525 unsigned char *description
;
1526 unsigned char *desc_sep
;
1527 unsigned char *format
, *text
, *title
;
1529 #define TYPE_QUERY_WIDGETS_COUNT 8
1530 int widgets
= TYPE_QUERY_WIDGETS_COUNT
;
1531 struct terminal
*term
= type_query
->ses
->tab
->term
;
1532 struct memory_list
*ml
;
1533 struct dialog_data
*dlg_data
;
1534 int selected_widget
;
1536 mem_free_set(&type_query
->external_handler
, NULL
);
1539 type_query
->block
= handler
->block
;
1540 type_query
->copiousoutput
= handler
->copiousoutput
;
1541 if (!handler
->ask
) {
1542 type_query
->external_handler
= stracpy(handler
->program
);
1543 tp_open(type_query
);
1547 /* Start preparing for the type query dialog. */
1548 description
= handler
->description
;
1549 desc_sep
= *description
? "; " : "";
1550 title
= N_("What to do?");
1553 title
= N_("Unknown type");
1558 dlg
= calloc_dialog(TYPE_QUERY_WIDGETS_COUNT
, MAX_STR_LEN
* 2);
1561 if (init_string(&filename
)) {
1562 add_mime_filename_to_string(&filename
, type_query
->uri
);
1564 /* Let's make the filename pretty for display & save */
1565 /* TODO: The filename can be the empty string here. See bug 396. */
1568 decode_uri_string(&filename
);
1570 #endif /* CONFIG_UTF8 */
1571 decode_uri_string_for_display(&filename
);
1574 text
= get_dialog_offset(dlg
, TYPE_QUERY_WIDGETS_COUNT
);
1575 /* For "default directory index pages" with wrong content-type
1576 * the filename can be NULL, e.g. http://www.spamhaus.org in bug 396. */
1577 if (filename
.length
) {
1578 format
= _("What would you like to do with the file '%s' (type: %s%s%s)?", term
);
1579 snprintf(text
, MAX_STR_LEN
, format
, filename
.source
, ct
, desc_sep
, description
);
1581 format
= _("What would you like to do with the file (type: %s%s%s)?", term
);
1582 snprintf(text
, MAX_STR_LEN
, format
, ct
, desc_sep
, description
);
1585 done_string(&filename
);
1587 dlg
->title
= _(title
, term
);
1588 dlg
->layouter
= generic_dialog_layouter
;
1589 dlg
->layout
.padding_top
= 1;
1590 dlg
->layout
.fit_datalen
= 1;
1591 dlg
->udata2
= type_query
;
1593 add_dlg_text(dlg
, text
, ALIGN_LEFT
, 0);
1595 /* Add input field or text widget with info about the program handler. */
1596 if (!get_cmd_opt_bool("anonymous")) {
1597 unsigned char *field
= mem_calloc(1, MAX_STR_LEN
);
1604 if (handler
&& handler
->program
) {
1605 safe_strncpy(field
, handler
->program
, MAX_STR_LEN
);
1608 /* xgettext:no-c-format */
1609 add_dlg_field(dlg
, _("Program ('%' will be replaced by the filename)", term
),
1610 0, 0, NULL
, MAX_STR_LEN
, field
, NULL
);
1611 type_query
->external_handler
= field
;
1613 add_dlg_checkbox(dlg
, _("Block the terminal", term
), &type_query
->block
);
1614 selected_widget
= 3;
1616 } else if (handler
) {
1617 unsigned char *field
= text
+ MAX_STR_LEN
;
1619 format
= _("The file will be opened with the program '%s'.", term
);
1620 snprintf(field
, MAX_STR_LEN
, format
, handler
->program
);
1621 add_dlg_text(dlg
, field
, ALIGN_LEFT
, 0);
1623 type_query
->external_handler
= stracpy(handler
->program
);
1624 if (!type_query
->external_handler
) {
1630 selected_widget
= 2;
1634 selected_widget
= 1;
1637 /* Add buttons if they are both usable and allowed. */
1639 if (!get_cmd_opt_bool("anonymous") || handler
) {
1640 add_dlg_ok_button(dlg
, _("~Open", term
), B_ENTER
,
1641 (done_handler_T
*) tp_open
, type_query
);
1646 if (!get_cmd_opt_bool("anonymous")) {
1647 add_dlg_ok_button(dlg
, _("Sa~ve", term
), B_ENTER
,
1648 (done_handler_T
*) tp_save
, type_query
);
1653 add_dlg_ok_button(dlg
, _("~Display", term
), B_ENTER
,
1654 (done_handler_T
*) tp_display
, type_query
);
1656 if (type_query
->cached
&& type_query
->cached
->head
) {
1657 add_dlg_button(dlg
, _("Show ~header", term
), B_ENTER
,
1658 tp_show_header
, type_query
);
1663 add_dlg_ok_button(dlg
, _("~Cancel", term
), B_ESC
,
1664 (done_handler_T
*) tp_cancel
, type_query
);
1666 add_dlg_end(dlg
, widgets
);
1668 ml
= getml(dlg
, (void *) NULL
);
1670 /* XXX: Assume that the allocated @external_handler will be
1671 * freed when releasing the @type_query. */
1676 dlg_data
= do_dialog(term
, dlg
, ml
);
1677 /* Don't focus the text field; we want the user to be able
1678 * to select a button by typing the first letter of its label
1679 * without having to first leave the text field. */
1681 select_widget_by_id(dlg_data
, selected_widget
);
1686 unsigned char *type
;
1687 unsigned int plain
:1;
1688 } static const known_types
[] = {
1690 { "text/plain", 1 },
1691 { "application/xhtml+xml", 0 }, /* RFC 3236 */
1693 { "application/docbook+xml", 1 },
1694 { "application/rss+xml", 0 },
1695 { "application/xbel+xml", 1 },
1696 { "application/xbel", 1 },
1697 { "application/x-xbel", 1 },
1702 /*! @relates type_query */
1704 setup_download_handler(struct session
*ses
, struct download
*loading
,
1705 struct cache_entry
*cached
, int frame
)
1707 struct mime_handler
*handler
;
1708 struct view_state
*vs
;
1709 struct type_query
*type_query
;
1710 unsigned char *ctype
= get_content_type(cached
);
1715 if (!ctype
|| !*ctype
)
1716 goto plaintext_follow
;
1718 for (i
= 0; known_types
[i
].type
; i
++) {
1719 if (c_strcasecmp(ctype
, known_types
[i
].type
))
1722 plaintext
= known_types
[i
].plain
;
1723 goto plaintext_follow
;
1726 xwin
= ses
->tab
->term
->environment
& ENV_XWIN
;
1727 handler
= get_mime_type_handler(ctype
, xwin
);
1729 if (!handler
&& strlen(ctype
) >= 4 && !c_strncasecmp(ctype
, "text", 4))
1730 goto plaintext_follow
;
1732 type_query
= find_type_query(ses
);
1736 type_query
= init_type_query(ses
, loading
, cached
);
1739 #ifdef CONFIG_BITTORRENT
1740 /* A terrible waste of a good MIME handler here, but we want
1741 * to use the type_query this is easier. */
1742 if ((!c_strcasecmp(ctype
, "application/x-bittorrent")
1743 || !c_strcasecmp(ctype
, "application/x-torrent"))
1744 && !get_cmd_opt_bool("anonymous"))
1745 query_bittorrent_dialog(type_query
);
1748 do_type_query(type_query
, ctype
, handler
);
1752 mem_free_if(handler
);
1757 vs
= ses_forward(ses
, frame
);
1758 if (vs
) vs
->plain
= plaintext
;