1 /** Sessions managment - you'll find things here which you wouldn't expect
14 #include "bfu/dialog.h"
15 #include "bookmarks/bookmarks.h"
16 #include "cache/cache.h"
17 #include "config/home.h"
18 #include "config/options.h"
19 #include "dialogs/menu.h"
20 #include "dialogs/status.h"
21 #include "document/document.h"
22 #include "document/html/frames.h"
23 #include "document/refresh.h"
24 #include "document/renderer.h"
25 #include "document/view.h"
26 #include "globhist/globhist.h"
27 #include "intl/gettext/libintl.h"
28 #include "main/event.h"
29 #include "main/object.h"
30 #include "main/timer.h"
31 #include "network/connection.h"
32 #include "network/state.h"
33 #include "osdep/newwin.h"
34 #include "protocol/http/blacklist.h"
35 #include "protocol/protocol.h"
36 #include "protocol/uri.h"
37 #ifdef CONFIG_SCRIPTING_SPIDERMONKEY
38 # include "scripting/smjs/smjs.h"
40 #include "session/download.h"
41 #include "session/history.h"
42 #include "session/location.h"
43 #include "session/session.h"
44 #include "session/task.h"
45 #include "terminal/tab.h"
46 #include "terminal/terminal.h"
47 #include "terminal/window.h"
48 #include "util/conv.h"
49 #include "util/error.h"
50 #include "util/memlist.h"
51 #include "util/memory.h"
52 #include "util/string.h"
53 #include "util/time.h"
54 #include "viewer/text/draw.h"
55 #include "viewer/text/form.h"
56 #include "viewer/text/link.h"
57 #include "viewer/text/view.h"
61 LIST_HEAD(struct file_to_load
);
64 unsigned int req_sent
:1;
66 struct cache_entry
*cached
;
67 unsigned char *target_frame
;
69 struct download download
;
72 /** This structure and related functions are used to maintain information
73 * for instances opened in new windows. We store all related session info like
74 * URI and base session to clone from so that when the new instance connects
75 * we can look up this information. In case of failure the session information
78 LIST_HEAD(struct session_info
);
86 enum cache_mode cache_mode
;
89 #define file_to_load_is_active(ftl) ((ftl)->req_sent && is_in_progress_state((ftl)->download.state))
92 INIT_LIST_OF(struct session
, sessions
);
94 enum remote_session_flags remote_session_flags
;
97 static struct file_to_load
*request_additional_file(struct session
*,
101 static window_handler_T tabwin_func
;
104 static INIT_LIST_OF(struct session_info
, session_info
);
105 static int session_info_id
= 1;
107 static struct session_info
*
108 get_session_info(int id
)
110 struct session_info
*info
;
112 foreach (info
, session_info
) {
115 if (info
->id
!= id
) continue;
117 /* Make sure the info->ses session is still with us. */
118 foreach (ses
, sessions
)
119 if (ses
== info
->ses
)
130 done_session_info(struct session_info
*info
)
133 kill_timer(&info
->timer
);
135 if (info
->uri
) done_uri(info
->uri
);
136 if (info
->referrer
) done_uri(info
->referrer
);
141 done_saved_session_info(void)
143 while (!list_empty(session_info
))
144 done_session_info(session_info
.next
);
147 /** Timer callback for session_info.timer. As explained in install_timer(),
148 * this function must erase the expired timer ID from all variables. */
150 session_info_timeout(int id
)
152 struct session_info
*info
= get_session_info(id
);
155 info
->timer
= TIMER_ID_UNDEF
;
156 /* The expired timer ID has now been erased. */
157 done_session_info(info
);
161 add_session_info(struct session
*ses
, struct uri
*uri
, struct uri
*referrer
,
162 enum cache_mode cache_mode
, enum task_type task
)
164 struct session_info
*info
= mem_calloc(1, sizeof(*info
));
166 if (!info
) return -1;
168 info
->id
= session_info_id
++;
169 /* I don't know what a reasonable start up time for a new instance is
170 * but it won't hurt to have a few seconds atleast. --jonas */
171 install_timer(&info
->timer
, (milliseconds_T
) 10000,
172 (void (*)(void *)) session_info_timeout
,
173 (void *) (long) info
->id
);
177 info
->cache_mode
= cache_mode
;
179 if (uri
) info
->uri
= get_uri_reference(uri
);
180 if (referrer
) info
->referrer
= get_uri_reference(referrer
);
182 add_to_list(session_info
, info
);
187 static struct session
*
188 init_saved_session(struct terminal
*term
, int id
)
190 struct session_info
*info
= get_session_info(id
);
193 if (!info
) return NULL
;
195 ses
= init_session(info
->ses
, term
, info
->uri
, 0);
198 done_session_info(info
);
202 /* Only do the ses_goto()-thing for target=_blank. */
203 if (info
->uri
&& info
->task
!= TASK_NONE
) {
204 /* The init_session() call would have started the download but
205 * not with the requested cache mode etc. so interrupt that
207 abort_loading(ses
, 1);
209 ses
->reloadlevel
= info
->cache_mode
;
210 set_session_referrer(ses
, info
->referrer
);
211 ses_goto(ses
, info
->uri
, NULL
, NULL
, info
->cache_mode
,
215 done_session_info(info
);
220 static struct session
*
221 get_master_session(void)
225 foreach (ses
, sessions
)
226 if (ses
->tab
->term
->master
) {
227 struct window
*current_tab
= get_current_tab(ses
->tab
->term
);
229 return current_tab
? current_tab
->data
: NULL
;
235 /** @relates session */
237 get_current_download(struct session
*ses
)
239 struct download
*download
= NULL
;
241 if (!ses
) return NULL
;
244 download
= &ses
->loading
;
245 else if (have_location(ses
))
246 download
= &cur_loc(ses
)->download
;
248 if (download
&& is_in_state(download
->state
, S_OK
)) {
249 struct file_to_load
*ftl
;
251 foreach (ftl
, ses
->more_files
)
252 if (file_to_load_is_active(ftl
))
253 return &ftl
->download
;
256 /* Note that @download isn't necessarily NULL here,
257 * if @ses->more_files is empty. -- Miciah */
262 done_retry_connection_without_verification(void *data
)
264 struct delayed_open
*deo
= (struct delayed_open
*)data
;
273 retry_connection_without_verification(void *data
)
275 struct delayed_open
*deo
= (struct delayed_open
*)data
;
278 if (deo
->uri
->hostlen
) {
279 add_blacklist_entry(deo
->uri
, SERVER_BLACKLIST_NO_CERT_VERIFY
);
281 goto_uri(deo
->ses
, deo
->uri
);
288 print_error_dialog(struct session
*ses
, struct connection_state state
,
289 struct uri
*uri
, enum connection_priority priority
)
292 unsigned char *uristring
;
294 /* Don't show error dialogs for missing CSS stylesheets */
295 if (priority
== PRI_CSS
296 || !init_string(&msg
))
299 uristring
= uri
? get_uri_string(uri
, URI_PUBLIC
) : NULL
;
302 if (ses
->tab
->term
->utf8_cp
)
303 decode_uri(uristring
);
305 #endif /* CONFIG_UTF8 */
306 decode_uri_for_display(uristring
);
307 add_format_to_string(&msg
,
308 _("Unable to retrieve %s", ses
->tab
->term
),
311 add_to_string(&msg
, ":\n\n");
314 add_to_string(&msg
, get_state_message(state
, ses
->tab
->term
));
316 if (!uri
|| uri
->protocol
!= PROTOCOL_HTTPS
) {
317 info_box(ses
->tab
->term
, MSGBOX_FREE_TEXT
,
318 N_("Error"), ALIGN_CENTER
,
321 struct delayed_open
*deo
= mem_calloc(1, sizeof(*deo
));
325 add_to_string(&msg
, "\n\n");
326 add_to_string(&msg
, N_("Retry without verification?"));
328 deo
->uri
= get_uri_reference(uri
);
330 msg_box(ses
->tab
->term
, NULL
, MSGBOX_FREE_TEXT
,
331 N_("Error"), ALIGN_CENTER
,
334 MSG_BOX_BUTTON(N_("~Yes"), retry_connection_without_verification
, B_ENTER
),
335 MSG_BOX_BUTTON(N_("~No"), done_retry_connection_without_verification
, B_ESC
));
342 abort_files_load(struct session
*ses
, int interrupt
)
345 struct file_to_load
*ftl
;
348 foreach (ftl
, ses
->more_files
) {
349 if (!file_to_load_is_active(ftl
))
353 cancel_download(&ftl
->download
, interrupt
);
361 free_files(struct session
*ses
)
363 struct file_to_load
*ftl
;
365 abort_files_load(ses
, 0);
366 foreach (ftl
, ses
->more_files
) {
367 if (ftl
->cached
) object_unlock(ftl
->cached
);
368 if (ftl
->uri
) done_uri(ftl
->uri
);
369 mem_free_if(ftl
->target_frame
);
371 free_list(ses
->more_files
);
377 static void request_frameset(struct session
*, struct frameset_desc
*, int);
380 request_frame(struct session
*ses
, unsigned char *name
,
381 struct uri
*uri
, int depth
)
383 struct location
*loc
= cur_loc(ses
);
386 assertm(have_location(ses
), "request_frame: no location");
387 if_assert_failed
return;
389 foreach (frame
, loc
->frames
) {
390 struct document_view
*doc_view
;
392 if (c_strcasecmp(frame
->name
, name
))
395 foreach (doc_view
, ses
->scrn_frames
) {
396 if (doc_view
->vs
== &frame
->vs
&& doc_view
->document
->frame_desc
) {
397 request_frameset(ses
, doc_view
->document
->frame_desc
, depth
);
402 request_additional_file(ses
, name
, frame
->vs
.uri
, PRI_FRAME
);
406 frame
= mem_calloc(1, sizeof(*frame
));
409 frame
->name
= stracpy(name
);
415 init_vs(&frame
->vs
, uri
, -1);
417 add_to_list(loc
->frames
, frame
);
419 request_additional_file(ses
, name
, frame
->vs
.uri
, PRI_FRAME
);
423 request_frameset(struct session
*ses
, struct frameset_desc
*frameset_desc
, int depth
)
427 if (depth
> HTML_MAX_FRAME_DEPTH
) return;
429 depth
++; /* Inheritation counter (recursion brake ;) */
431 for (i
= 0; i
< frameset_desc
->n
; i
++) {
432 struct frame_desc
*frame_desc
= &frameset_desc
->frame_desc
[i
];
434 if (frame_desc
->subframe
) {
435 request_frameset(ses
, frame_desc
->subframe
, depth
);
436 } else if (frame_desc
->name
&& frame_desc
->uri
) {
437 request_frame(ses
, frame_desc
->name
,
438 frame_desc
->uri
, depth
);
445 load_css_imports(struct session
*ses
, struct document_view
*doc_view
)
447 struct document
*document
= doc_view
->document
;
451 if (!document
) return;
453 foreach_uri (uri
, index
, &document
->css_imports
) {
454 request_additional_file(ses
, "", uri
, PRI_CSS
);
458 #define load_css_imports(ses, doc_view)
461 #ifdef CONFIG_ECMASCRIPT
463 load_ecmascript_imports(struct session
*ses
, struct document_view
*doc_view
)
465 struct document
*document
= doc_view
->document
;
469 if (!document
) return;
471 foreach_uri (uri
, index
, &document
->ecmascript_imports
) {
472 request_additional_file(ses
, "", uri
, /* XXX */ PRI_CSS
);
476 #define load_ecmascript_imports(ses, doc_view)
479 NONSTATIC_INLINE
void
480 load_frames(struct session
*ses
, struct document_view
*doc_view
)
482 struct document
*document
= doc_view
->document
;
484 if (!document
|| !document
->frame_desc
) return;
485 request_frameset(ses
, document
->frame_desc
, 0);
487 foreach (doc_view
, ses
->scrn_frames
) {
488 load_css_imports(ses
, doc_view
);
489 load_ecmascript_imports(ses
, doc_view
);
493 /** Timer callback for session.display_timer. As explained in install_timer(),
494 * this function must erase the expired timer ID from all variables. */
496 display_timer(struct session
*ses
)
498 timeval_T start
, stop
, duration
;
502 draw_formatted(ses
, 3);
504 timeval_sub(&duration
, &start
, &stop
);
506 t
= mult_ms(timeval_to_milliseconds(&duration
), DISPLAY_TIME
);
507 if (t
< DISPLAY_TIME_MIN
) t
= DISPLAY_TIME_MIN
;
508 install_timer(&ses
->display_timer
, t
,
509 (void (*)(void *)) display_timer
,
511 /* The expired timer ID has now been erased. */
513 load_frames(ses
, ses
->doc_view
);
514 load_css_imports(ses
, ses
->doc_view
);
515 load_ecmascript_imports(ses
, ses
->doc_view
);
516 process_file_requests(ses
);
520 struct questions_entry
{
521 LIST_HEAD(struct questions_entry
);
523 void (*callback
)(struct session
*, void *);
527 INIT_LIST_OF(struct questions_entry
, questions_queue
);
531 check_questions_queue(struct session
*ses
)
533 while (!list_empty(questions_queue
)) {
534 struct questions_entry
*q
= questions_queue
.next
;
536 q
->callback(ses
, q
->data
);
543 add_questions_entry(void (*callback
)(struct session
*, void *), void *data
)
545 struct questions_entry
*q
= mem_alloc(sizeof(*q
));
549 q
->callback
= callback
;
551 add_to_list(questions_queue
, q
);
554 #ifdef CONFIG_SCRIPTING
556 maybe_pre_format_html(struct cache_entry
*cached
, struct session
*ses
)
558 struct fragment
*fragment
;
559 static int pre_format_html_event
= EVENT_NONE
;
561 if (!cached
|| cached
->preformatted
)
564 /* The script called from here may indirectly call
565 * garbage_collection(). If the refcount of the cache entry
566 * were 0, it could then be freed, and the
567 * cached->preformatted assignment at the end of this function
568 * would crash. Normally, the document has a reference to the
569 * cache entry, and that suffices. However, if the cache
570 * entry was loaded to satisfy e.g. USEMAP="imgmap.html#map",
571 * then cached->object.refcount == 0 here, and must be
574 * cached->object.refcount == 0 is safe while the cache entry
575 * is being loaded, because garbage_collection() calls
576 * is_entry_used(), which checks whether any connection is
577 * using the cache entry. But loading has ended before this
581 fragment
= get_cache_fragment(cached
);
582 if (!fragment
) goto unlock_and_return
;
584 /* We cannot do anything if the data are fragmented. */
585 if (!list_is_singleton(cached
->frag
)) goto unlock_and_return
;
587 set_event_id(pre_format_html_event
, "pre-format-html");
588 trigger_event(pre_format_html_event
, ses
, cached
);
590 /* XXX: Keep this after the trigger_event, because hooks might call
591 * normalize_cache_entry()! */
592 cached
->preformatted
= 1;
595 object_unlock(cached
);
600 check_incomplete_redirects(struct cache_entry
*cached
)
604 cached
= follow_cached_redirects(cached
);
605 if (cached
&& !cached
->redirect
) {
606 /* XXX: This is not quite true, but does that difference
608 return cached
->incomplete
;
615 session_is_loading(struct session
*ses
)
617 struct download
*download
= get_current_download(ses
);
619 if (!download
) return 0;
621 if (!is_in_result_state(download
->state
))
624 /* The validness of download->cached (especially the download struct in
625 * ses->loading) is hard to maintain so check before using it.
626 * Related to bug 559. */
628 && cache_entry_is_valid(download
->cached
)
629 && check_incomplete_redirects(download
->cached
))
636 doc_loading_callback(struct download
*download
, struct session
*ses
)
640 if (is_in_result_state(download
->state
)) {
641 #ifdef CONFIG_SCRIPTING
642 maybe_pre_format_html(download
->cached
, ses
);
644 kill_timer(&ses
->display_timer
);
646 draw_formatted(ses
, 1);
648 if (get_cmd_opt_bool("auto-submit")) {
649 if (!list_empty(ses
->doc_view
->document
->forms
)) {
650 get_cmd_opt_bool("auto-submit") = 0;
655 load_frames(ses
, ses
->doc_view
);
656 load_css_imports(ses
, ses
->doc_view
);
657 load_ecmascript_imports(ses
, ses
->doc_view
);
658 process_file_requests(ses
);
660 start_document_refreshes(ses
);
662 if (!is_in_state(download
->state
, S_OK
)) {
663 print_error_dialog(ses
, download
->state
,
664 ses
->doc_view
->document
->uri
,
668 } else if (is_in_transfering_state(download
->state
)
669 && ses
->display_timer
== TIMER_ID_UNDEF
) {
673 check_questions_queue(ses
);
674 print_screen_status(ses
);
676 #ifdef CONFIG_GLOBHIST
677 if (download
->pri
!= PRI_CSS
) {
678 unsigned char *title
= ses
->doc_view
->document
->title
;
682 uri
= download
->conn
->proxied_uri
;
683 else if (download
->cached
)
684 uri
= download
->cached
->uri
;
689 add_global_history_item(struri(uri
), title
, time(NULL
));
693 if (submit
) auto_submit_form(ses
);
697 file_loading_callback(struct download
*download
, struct file_to_load
*ftl
)
699 if (ftl
->download
.cached
&& ftl
->cached
!= ftl
->download
.cached
) {
700 if (ftl
->cached
) object_unlock(ftl
->cached
);
701 ftl
->cached
= ftl
->download
.cached
;
702 object_lock(ftl
->cached
);
705 /* FIXME: We need to do content-type check here! However, we won't
706 * handle properly the "Choose action" dialog now :(. */
707 if (ftl
->cached
&& !ftl
->cached
->redirect_get
&& download
->pri
!= PRI_CSS
) {
708 struct session
*ses
= ftl
->ses
;
709 struct uri
*loading_uri
= ses
->loading_uri
;
710 unsigned char *target_frame
= null_or_stracpy(ses
->task
.target
.frame
);
712 ses
->loading_uri
= ftl
->uri
;
713 mem_free_set(&ses
->task
.target
.frame
, null_or_stracpy(ftl
->target_frame
));
714 setup_download_handler(ses
, &ftl
->download
, ftl
->cached
, 1);
715 ses
->loading_uri
= loading_uri
;
716 mem_free_set(&ses
->task
.target
.frame
, target_frame
);
719 doc_loading_callback(download
, ftl
->ses
);
722 static struct file_to_load
*
723 request_additional_file(struct session
*ses
, unsigned char *name
, struct uri
*uri
, int pri
)
725 struct file_to_load
*ftl
;
727 if (uri
->protocol
== PROTOCOL_UNKNOWN
) {
731 /* XXX: We cannot run the external handler here, because
732 * request_additional_file() is called many times for a single URL
733 * (normally the foreach() right below catches them all). Anyway,
734 * having <frame src="mailto:foo"> would be just weird, wouldn't it?
736 if (get_protocol_external_handler(ses
->tab
->term
, uri
)) {
740 foreach (ftl
, ses
->more_files
) {
741 if (compare_uri(ftl
->uri
, uri
, URI_BASE
)) {
742 if (ftl
->pri
> pri
) {
744 move_download(&ftl
->download
, &ftl
->download
, pri
);
750 ftl
= mem_calloc(1, sizeof(*ftl
));
751 if (!ftl
) return NULL
;
753 ftl
->uri
= get_uri_reference(uri
);
754 ftl
->target_frame
= stracpy(name
);
755 ftl
->download
.callback
= (download_callback_T
*) file_loading_callback
;
756 ftl
->download
.data
= ftl
;
760 add_to_list(ses
->more_files
, ftl
);
766 load_additional_file(struct file_to_load
*ftl
, enum cache_mode cache_mode
)
768 struct document_view
*doc_view
= current_frame(ftl
->ses
);
769 struct uri
*referrer
= doc_view
&& doc_view
->document
770 ? doc_view
->document
->uri
: NULL
;
772 load_uri(ftl
->uri
, referrer
, &ftl
->download
, ftl
->pri
, cache_mode
, -1);
776 process_file_requests(struct session
*ses
)
778 if (ses
->status
.processing_file_requests
) return;
779 ses
->status
.processing_file_requests
= 1;
782 struct file_to_load
*ftl
;
785 foreach (ftl
, ses
->more_files
) {
791 load_additional_file(ftl
, CACHE_MODE_NORMAL
);
798 ses
->status
.processing_file_requests
= 0;
803 dialog_goto_url_open(void *data
)
805 dialog_goto_url((struct session
*) data
, NULL
);
808 /** @returns 0 if the first session was not properly initialized and
809 * setup_session() should be called on the session as well. */
811 setup_first_session(struct session
*ses
, struct uri
*uri
)
813 /* [gettext_accelerator_context(setup_first_session)] */
814 struct terminal
*term
= ses
->tab
->term
;
816 if (!*get_opt_str("protocol.http.user_agent", NULL
)) {
818 N_("Warning"), ALIGN_CENTER
,
819 N_("You have an empty string in protocol.http.user_agent - "
820 "this was a default value in the past, substituted by "
821 "default ELinks User-Agent string. However, currently "
822 "this means that NO User-Agent HEADER "
823 "WILL BE SENT AT ALL - if this is really what you want, "
824 "set its value to \" \", otherwise please delete the line "
825 "with this setting from your configuration file (if you "
826 "have no idea what I'm talking about, just do this), so "
827 "that the correct default setting will be used. Apologies for "
828 "any inconvience caused."));
831 if (!get_opt_bool("config.saving_style_w", NULL
)) {
832 struct option
*opt
= get_opt_rec(config_options
, "config.saving_style_w");
833 opt
->value
.number
= 1;
834 option_changed(ses
, opt
);
835 if (get_opt_int("config.saving_style", NULL
) != 3) {
837 N_("Warning"), ALIGN_CENTER
,
838 N_("You have option config.saving_style set to "
839 "a de facto obsolete value. The configuration "
840 "saving algorithms of ELinks were changed from "
841 "the last time you upgraded ELinks. Now, only "
842 "those options which you actually changed are "
843 "saved to the configuration file, instead of "
844 "all the options. This simplifies our "
845 "situation greatly when we see that some option "
846 "has an inappropriate default value or we need to "
847 "change the semantics of some option in a subtle way. "
848 "Thus, we recommend you change the value of "
849 "config.saving_style option to 3 in order to get "
850 "the \"right\" behaviour. Apologies for any "
851 "inconvience caused."));
856 /* Only open the goto URL dialog if no URI was passed on the
858 void *handler
= uri
? NULL
: dialog_goto_url_open
;
862 msg_box(term
, NULL
, 0,
863 N_("Welcome"), ALIGN_CENTER
,
864 N_("Welcome to ELinks!\n\n"
865 "Press ESC for menu. Documentation is available in "
868 MSG_BOX_BUTTON(N_("~OK"), handler
, B_ENTER
| B_ESC
));
870 /* If there is no URI the goto dialog will pop up so there is
871 * no need to call setup_session(). */
874 #ifdef CONFIG_BOOKMARKS
875 } else if (!uri
&& get_opt_bool("ui.sessions.auto_restore", NULL
)) {
876 unsigned char *folder
; /* UTF-8 */
878 folder
= get_auto_save_bookmark_foldername_utf8();
880 open_bookmark_folder(ses
, folder
);
887 /* If there's a URI to load we have to call */
891 /** First load the current URI of the base session. In most cases it will just
892 * be fetched from the cache so that the new tab will not appear ``empty' while
893 * loading the real URI or showing the goto URL dialog. */
895 setup_session(struct session
*ses
, struct uri
*uri
, struct session
*base
)
897 if (base
&& have_location(base
)) {
898 ses_load(ses
, get_uri_reference(cur_loc(base
)->vs
.uri
),
899 NULL
, NULL
, CACHE_MODE_ALWAYS
, TASK_FORWARD
);
900 if (ses
->doc_view
&& ses
->doc_view
->vs
901 && base
->doc_view
&& base
->doc_view
->vs
) {
902 struct view_state
*vs
= ses
->doc_view
->vs
;
905 copy_vs(vs
, base
->doc_view
->vs
);
907 ses
->doc_view
->vs
= vs
;
914 } else if (!goto_url_home(ses
)) {
915 if (get_opt_bool("ui.startup_goto_dialog", NULL
)) {
916 dialog_goto_url_open(ses
);
921 /** @relates session */
923 init_session(struct session
*base_session
, struct terminal
*term
,
924 struct uri
*uri
, int in_background
)
926 struct session
*ses
= mem_calloc(1, sizeof(*ses
));
928 if (!ses
) return NULL
;
930 ses
->tab
= init_tab(term
, ses
, tabwin_func
);
936 ses
->option
= copy_option(config_options
,
937 CO_SHALLOW
| CO_NO_LISTBOX_ITEM
);
938 create_history(&ses
->history
);
939 init_list(ses
->scrn_frames
);
940 init_list(ses
->more_files
);
941 init_list(ses
->type_queries
);
942 ses
->task
.type
= TASK_NONE
;
943 ses
->display_timer
= TIMER_ID_UNDEF
;
946 init_led_panel(&ses
->status
.leds
);
947 ses
->status
.ssl_led
= register_led(ses
, 0);
948 ses
->status
.insert_mode_led
= register_led(ses
, 1);
949 ses
->status
.ecmascript_led
= register_led(ses
, 2);
950 ses
->status
.popup_led
= register_led(ses
, 3);
952 ses
->status
.download_led
= register_led(ses
, 5);
954 ses
->status
.force_show_status_bar
= -1;
955 ses
->status
.force_show_title_bar
= -1;
957 add_to_list(sessions
, ses
);
959 /* Update the status -- most importantly the info about whether to the
960 * show the title, tab and status bar -- _before_ loading the URI so
961 * the document cache is not filled with useless documents if the
962 * content is already cached.
964 * For big document it also reduces memory usage quite a bit because
965 * (atleast that is my interpretation --jonas) the old document will
966 * have a chance to be released before rendering a new one. A few
967 * numbers when opening a new tab while viewing debians package list
970 * 9307 jonas 15 0 34252 30m 5088 S 0.0 12.2 0:03.63 elinks-old
971 * 9305 jonas 15 0 17060 13m 5088 S 0.0 5.5 0:02.07 elinks-new
975 /* Check if the newly inserted session is the only in the list and do
976 * the special setup for the first session, */
977 if (!list_is_singleton(sessions
) || !setup_first_session(ses
, uri
)) {
978 setup_session(ses
, uri
, base_session
);
982 switch_to_tab(term
, get_tab_number(ses
->tab
), -1);
984 if (!term
->main_menu
) activate_bfu_technology(ses
, -1);
989 init_remote_session(struct session
*ses
, enum remote_session_flags
*remote_ptr
,
992 enum remote_session_flags remote
= *remote_ptr
;
994 if (remote
& SES_REMOTE_CURRENT_TAB
) {
996 /* Mask out the current tab flag */
997 *remote_ptr
= remote
& ~SES_REMOTE_CURRENT_TAB
;
999 /* Remote session was masked out. Open all following URIs in
1002 *remote_ptr
= SES_REMOTE_NEW_TAB
;
1004 } else if (remote
& SES_REMOTE_NEW_TAB
) {
1005 /* FIXME: This is not perfect. Doing multiple -remote
1006 * with no URLs will make the goto dialogs
1007 * inaccessible. Maybe we should not support this kind
1008 * of thing or make the window focus detecting code
1009 * more intelligent. --jonas */
1010 open_uri_in_new_tab(ses
, uri
, 0, 0);
1012 if (remote
& SES_REMOTE_PROMPT_URL
) {
1013 dialog_goto_url_open(ses
);
1016 } else if (remote
& SES_REMOTE_NEW_WINDOW
) {
1017 /* FIXME: It is quite rude because we just take the first
1018 * possibility and should maybe make it possible to specify
1019 * new-screen etc via -remote "openURL(..., new-*)" --jonas */
1020 if (!can_open_in_new(ses
->tab
->term
))
1023 open_uri_in_new_window(ses
, uri
, NULL
,
1024 ses
->tab
->term
->environment
,
1025 CACHE_MODE_NORMAL
, TASK_NONE
);
1027 } else if (remote
& SES_REMOTE_ADD_BOOKMARK
) {
1028 #ifdef CONFIG_BOOKMARKS
1032 /** @todo Bug 1066: What is the encoding of struri()?
1033 * This code currently assumes the system charset.
1034 * It might be best to keep URIs in plain ASCII and
1035 * then have a function that reversibly converts them
1036 * to IRIs for display in a given encoding. */
1037 uri_cp
= get_cp_index("System");
1038 add_bookmark_cp(NULL
, 1, uri_cp
, struri(uri
), struri(uri
));
1041 } else if (remote
& SES_REMOTE_INFO_BOX
) {
1042 unsigned char *text
;
1046 text
= memacpy(uri
->data
, uri
->datalen
);
1049 info_box(ses
->tab
->term
, MSGBOX_FREE_TEXT
,
1050 N_("Error"), ALIGN_CENTER
,
1053 } else if (remote
& SES_REMOTE_PROMPT_URL
) {
1054 dialog_goto_url_open(ses
);
1056 } else if (remote
& SES_REMOTE_RELOAD
) {
1057 reload(ses
, CACHE_MODE_FORCE_RELOAD
);
1064 encode_session_info(struct string
*info
,
1065 LIST_OF(struct string_list_item
) *url_list
)
1067 struct string_list_item
*url
;
1069 if (!init_string(info
)) return NULL
;
1071 foreach (url
, *url_list
) {
1072 struct string
*str
= &url
->string
;
1074 add_bytes_to_string(info
, str
->source
, str
->length
+ 1);
1080 /** Older elinks versions (up to and including 0.9.1) sends no magic variable and if
1081 * this is detected we fallback to the old session info format. For this format
1082 * the magic member of terminal_info hold the length of the URI string. The
1083 * old format is handled by the default label in the switch.
1085 * The new session info format supports extraction of multiple URIS from the
1086 * terminal_info data member. The magic variable controls how to interpret
1089 * - INTERLINK_NORMAL_MAGIC means use the terminal_info session_info
1090 * variable as an id for a saved session.
1092 * - INTERLINK_REMOTE_MAGIC means use the terminal_info session_info
1093 * variable as the remote session flags. */
1095 decode_session_info(struct terminal
*term
, struct terminal_info
*info
)
1097 int len
= info
->length
;
1098 struct session
*base_session
= NULL
;
1099 enum remote_session_flags remote
= 0;
1102 switch (info
->magic
) {
1103 case INTERLINK_NORMAL_MAGIC
:
1104 /* Lookup if there are any saved sessions that should be
1105 * resumed using the session_info as an id. The id is derived
1106 * from the value of -base-session command line option in the
1107 * connecting instance.
1109 * At the moment it is only used when opening instances in new
1110 * window to figure out how to initialize it when the new
1111 * instance connects to the master.
1113 * We don't need to handle it for the old format since new
1114 * instances connecting this way will always be of the same
1115 * origin as the master. */
1116 if (init_saved_session(term
, info
->session_info
))
1120 case INTERLINK_REMOTE_MAGIC
:
1121 /* This could mean some fatal bug but I am unsure if we can
1122 * actually assert it since people could pour all kinds of crap
1123 * down the socket. */
1124 if (!info
->session_info
) {
1125 INTERNAL("Remote magic with no remote flags");
1129 remote
= info
->session_info
;
1131 /* If processing session info from a -remote instance we want
1132 * to hook up with the master so we can handle request for
1133 * stuff in current tab. */
1134 base_session
= get_master_session();
1135 if (!base_session
) return 0;
1140 /* The old format calculates the session_info and magic members
1141 * as part of the data that should be decoded so we have to
1142 * substract it to get the size of the actual URI data. */
1143 len
-= sizeof(info
->session_info
) + sizeof(info
->magic
);
1145 /* Extract URI containing @magic bytes */
1146 if (info
->magic
<= 0 || info
->magic
> len
)
1154 return !!init_session(base_session
, term
, NULL
, 0);
1156 /* Even though there are no URIs we still have to
1157 * handle remote stuff. */
1158 init_remote_session(base_session
, &remote
, NULL
);
1164 /* Extract multiple (possible) NUL terminated URIs */
1166 unsigned char *end
= memchr(str
, 0, len
);
1167 int urilength
= end
? end
- str
: len
;
1168 struct uri
*uri
= NULL
;
1169 unsigned char *uristring
= memacpy(str
, urilength
);
1172 uri
= get_hooked_uri(uristring
, base_session
, term
->cwd
);
1173 mem_free(uristring
);
1176 len
-= urilength
+ 1;
1177 str
+= urilength
+ 1;
1182 init_remote_session(base_session
, &remote
, uri
);
1185 int backgrounded
= !list_empty(term
->windows
);
1187 struct session
*ses
;
1190 uri
= get_uri("about:blank", 0);
1192 ses
= init_session(base_session
, term
, uri
, backgrounded
);
1194 /* End loop if initialization fails */
1196 } else if (bad_url
) {
1197 print_error_dialog(ses
, connection_state(S_BAD_URL
),
1203 if (uri
) done_uri(uri
);
1206 /* If we only initialized remote sessions or didn't manage to add any
1207 * new tabs return zero so the terminal will be destroyed ASAP. */
1208 return remote
? 0 : !list_empty(term
->windows
);
1213 abort_loading(struct session
*ses
, int interrupt
)
1215 if (have_location(ses
)) {
1216 struct location
*loc
= cur_loc(ses
);
1218 cancel_download(&loc
->download
, interrupt
);
1219 abort_files_load(ses
, interrupt
);
1221 abort_preloading(ses
, interrupt
);
1225 destroy_session(struct session
*ses
)
1227 struct document_view
*doc_view
;
1230 if_assert_failed
return;
1232 #ifdef CONFIG_SCRIPTING_SPIDERMONKEY
1233 smjs_detach_session_object(ses
);
1235 destroy_downloads(ses
);
1236 abort_loading(ses
, 0);
1238 if (ses
->doc_view
) {
1239 detach_formatted(ses
->doc_view
);
1240 mem_free(ses
->doc_view
);
1243 foreach (doc_view
, ses
->scrn_frames
)
1244 detach_formatted(doc_view
);
1246 free_list(ses
->scrn_frames
);
1248 destroy_history(&ses
->history
);
1249 set_session_referrer(ses
, NULL
);
1251 if (ses
->loading_uri
) done_uri(ses
->loading_uri
);
1253 kill_timer(&ses
->display_timer
);
1255 while (!list_empty(ses
->type_queries
))
1256 done_type_query(ses
->type_queries
.next
);
1258 if (ses
->download_uri
) done_uri(ses
->download_uri
);
1259 mem_free_if(ses
->search_word
);
1260 mem_free_if(ses
->last_search_word
);
1261 mem_free_if(ses
->status
.last_title
);
1262 #ifdef CONFIG_ECMASCRIPT
1263 mem_free_if(ses
->status
.window_status
);
1266 delete_option(ses
->option
);
1273 reload(struct session
*ses
, enum cache_mode cache_mode
)
1275 reload_frame(ses
, NULL
, cache_mode
);
1279 reload_frame(struct session
*ses
, unsigned char *name
,
1280 enum cache_mode cache_mode
)
1282 abort_loading(ses
, 0);
1284 if (cache_mode
== CACHE_MODE_INCREMENT
) {
1285 cache_mode
= CACHE_MODE_NEVER
;
1286 if (ses
->reloadlevel
< CACHE_MODE_NEVER
)
1287 cache_mode
= ++ses
->reloadlevel
;
1289 ses
->reloadlevel
= cache_mode
;
1292 if (have_location(ses
)) {
1293 struct location
*loc
= cur_loc(ses
);
1294 struct file_to_load
*ftl
;
1296 #ifdef CONFIG_ECMASCRIPT
1297 loc
->vs
.ecmascript_fragile
= 1;
1300 /* FIXME: When reloading use loading_callback and set up a
1301 * session task so that the reloading will work even when the
1302 * reloaded document contains redirects. This is needed atleast
1303 * when reloading HTTP auth document after the user has entered
1305 loc
->download
.data
= ses
;
1306 loc
->download
.callback
= (download_callback_T
*) doc_loading_callback
;
1308 mem_free_set(&ses
->task
.target
.frame
, null_or_stracpy(name
));
1310 load_uri(loc
->vs
.uri
, ses
->referrer
, &loc
->download
, PRI_MAIN
, cache_mode
, -1);
1312 foreach (ftl
, ses
->more_files
) {
1313 if (file_to_load_is_active(ftl
))
1316 ftl
->download
.data
= ftl
;
1317 ftl
->download
.callback
= (download_callback_T
*) file_loading_callback
;
1319 load_additional_file(ftl
, cache_mode
);
1326 ses_find_frame(struct session
*ses
, unsigned char *name
)
1328 struct location
*loc
= cur_loc(ses
);
1329 struct frame
*frame
;
1331 assertm(have_location(ses
), "ses_request_frame: no location yet");
1332 if_assert_failed
return NULL
;
1334 foreachback (frame
, loc
->frames
)
1335 if (!c_strcasecmp(frame
->name
, name
))
1342 set_session_referrer(struct session
*ses
, struct uri
*referrer
)
1344 if (ses
->referrer
) done_uri(ses
->referrer
);
1345 ses
->referrer
= referrer
? get_uri_reference(referrer
) : NULL
;
1349 tabwin_func(struct window
*tab
, struct term_event
*ev
)
1351 struct session
*ses
= tab
->data
;
1355 if (ses
) destroy_session(ses
);
1356 if (!list_empty(sessions
)) update_status();
1363 if (!ses
|| ses
->tab
!= get_current_tab(ses
->tab
->term
))
1366 draw_formatted(ses
, tab
->resize
);
1368 load_frames(ses
, ses
->doc_view
);
1369 process_file_requests(ses
);
1372 print_screen_status(ses
);
1377 /* This check is related to bug 296 */
1378 assert(ses
->tab
== get_current_tab(ses
->tab
->term
));
1379 send_event(ses
, ev
);
1385 * Gets the url being viewed by this session. Writes it into @a str.
1386 * A maximum of @a str_size bytes (including null) will be written.
1390 get_current_url(struct session
*ses
, unsigned char *str
, size_t str_size
)
1395 assert(str
&& str_size
> 0);
1397 uri
= have_location(ses
) ? cur_loc(ses
)->vs
.uri
: ses
->loading_uri
;
1399 /* Not looking or loading anything */
1400 if (!uri
) return NULL
;
1402 /* Ensure that the url size is not greater than str_size.
1403 * We can't just happily strncpy(str, here, str_size)
1404 * because we have to stop at POST_CHAR, not only at NULL. */
1405 length
= int_min(get_real_uri_length(uri
), str_size
- 1);
1407 return safe_strncpy(str
, struri(uri
), length
+ 1);
1411 * Gets the title of the page being viewed by this session. Writes it into
1412 * @a str. A maximum of @a str_size bytes (including null) will be written.
1416 get_current_title(struct session
*ses
, unsigned char *str
, size_t str_size
)
1418 struct document_view
*doc_view
= current_frame(ses
);
1420 assert(str
&& str_size
> 0);
1422 /* Ensure that the title is defined */
1423 /* TODO: Try globhist --jonas */
1424 if (doc_view
&& doc_view
->document
->title
)
1425 return safe_strncpy(str
, doc_view
->document
->title
, str_size
);
1431 * Gets the url of the link currently selected. Writes it into @a str.
1432 * A maximum of @a str_size bytes (including null) will be written.
1436 get_current_link_url(struct session
*ses
, unsigned char *str
, size_t str_size
)
1438 struct link
*link
= get_current_session_link(ses
);
1440 assert(str
&& str_size
> 0);
1442 if (!link
) return NULL
;
1444 return safe_strncpy(str
, link
->where
? link
->where
: link
->where_img
, str_size
);
1447 /** get_current_link_name: returns the name of the current link
1448 * (the text between @<A> and @</A>), @a str is a preallocated string,
1449 * @a str_size includes the null char.
1450 * @relates session */
1452 get_current_link_name(struct session
*ses
, unsigned char *str
, size_t str_size
)
1454 struct link
*link
= get_current_session_link(ses
);
1455 unsigned char *where
, *name
= NULL
;
1457 assert(str
&& str_size
> 0);
1459 if (!link
) return NULL
;
1461 where
= link
->where
? link
->where
: link
->where_img
;
1462 #ifdef CONFIG_GLOBHIST
1464 struct global_history_item
*item
;
1466 item
= get_global_history_item(where
);
1467 if (item
) name
= item
->title
;
1470 if (!name
) name
= get_link_name(link
);
1471 if (!name
) name
= where
;
1473 return safe_strncpy(str
, name
, str_size
);
1477 get_current_link_in_view(struct document_view
*doc_view
)
1479 struct link
*link
= get_current_link(doc_view
);
1481 return link
&& !link_is_form(link
) ? link
: NULL
;
1484 /** @relates session */
1486 get_current_session_link(struct session
*ses
)
1488 return get_current_link_in_view(current_frame(ses
));
1491 /** @relates session */
1493 eat_kbd_repeat_count(struct session
*ses
)
1495 int count
= ses
->kbdprefix
.repeat_count
;
1497 set_kbd_repeat_count(ses
, 0);
1499 /* Clear status bar when prefix is eaten (bug 930) */
1500 print_screen_status(ses
);
1504 /** @relates session */
1506 set_kbd_repeat_count(struct session
*ses
, int new_count
)
1508 int old_count
= ses
->kbdprefix
.repeat_count
;
1510 if (new_count
== old_count
)
1513 ses
->kbdprefix
.repeat_count
= new_count
;
1515 /* Update the status bar. */
1516 print_screen_status(ses
);
1518 /* Clear the old link highlighting. */
1519 draw_formatted(ses
, 0);
1521 if (new_count
!= 0) {
1522 struct document_view
*doc_view
= current_frame(ses
);
1524 highlight_links_with_prefixes_that_start_with_n(ses
->tab
->term
,