762: Instead of setting a bare pointer for task.target.frame always
[elinks.git] / src / session / session.c
blobd87e6a1ba7c947d8519d57a8adaabc84bd4b95ad
1 /** Sessions managment - you'll find things here which you wouldn't expect
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include "elinks.h"
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/protocol.h"
35 #include "protocol/uri.h"
36 #include "session/download.h"
37 #include "session/history.h"
38 #include "session/location.h"
39 #include "session/session.h"
40 #include "session/task.h"
41 #include "terminal/tab.h"
42 #include "terminal/terminal.h"
43 #include "terminal/window.h"
44 #include "util/conv.h"
45 #include "util/error.h"
46 #include "util/memlist.h"
47 #include "util/memory.h"
48 #include "util/string.h"
49 #include "util/time.h"
50 #include "viewer/text/draw.h"
51 #include "viewer/text/form.h"
52 #include "viewer/text/link.h"
53 #include "viewer/text/view.h"
56 struct file_to_load {
57 LIST_HEAD(struct file_to_load);
59 struct session *ses;
60 unsigned int req_sent:1;
61 int pri;
62 struct cache_entry *cached;
63 unsigned char *target_frame;
64 struct uri *uri;
65 struct download download;
68 /** This structure and related functions are used to maintain information
69 * for instances opened in new windows. We store all related session info like
70 * URI and base session to clone from so that when the new instance connects
71 * we can look up this information. In case of failure the session information
72 * has a timeout */
73 struct session_info {
74 LIST_HEAD(struct session_info);
76 int id;
77 timer_id_T timer;
78 struct session *ses;
79 struct uri *uri;
80 struct uri *referrer;
81 enum task_type task;
82 enum cache_mode cache_mode;
85 #define file_to_load_is_active(ftl) ((ftl)->req_sent && is_in_progress_state((ftl)->download.state))
88 INIT_LIST_OF(struct session, sessions);
90 enum remote_session_flags remote_session_flags;
93 static struct file_to_load *request_additional_file(struct session *,
94 unsigned char *,
95 struct uri *, int);
97 static window_handler_T tabwin_func;
100 static INIT_LIST_OF(struct session_info, session_info);
101 static int session_info_id = 1;
103 static struct session_info *
104 get_session_info(int id)
106 struct session_info *info;
108 foreach (info, session_info) {
109 struct session *ses;
111 if (info->id != id) continue;
113 /* Make sure the info->ses session is still with us. */
114 foreach (ses, sessions)
115 if (ses == info->ses)
116 return info;
118 info->ses = NULL;
119 return info;
122 return NULL;
125 static void
126 done_session_info(struct session_info *info)
128 del_from_list(info);
129 kill_timer(&info->timer);
131 if (info->uri) done_uri(info->uri);
132 if (info->referrer) done_uri(info->referrer);
133 mem_free(info);
136 void
137 done_saved_session_info(void)
139 while (!list_empty(session_info))
140 done_session_info(session_info.next);
143 /** Timer callback for session_info.timer. As explained in install_timer(),
144 * this function must erase the expired timer ID from all variables. */
145 static void
146 session_info_timeout(int id)
148 struct session_info *info = get_session_info(id);
150 if (!info) return;
151 info->timer = TIMER_ID_UNDEF;
152 /* The expired timer ID has now been erased. */
153 done_session_info(info);
157 add_session_info(struct session *ses, struct uri *uri, struct uri *referrer,
158 enum cache_mode cache_mode, enum task_type task)
160 struct session_info *info = mem_calloc(1, sizeof(*info));
162 if (!info) return -1;
164 info->id = session_info_id++;
165 /* I don't know what a reasonable start up time for a new instance is
166 * but it won't hurt to have a few seconds atleast. --jonas */
167 install_timer(&info->timer, (milliseconds_T) 10000,
168 (void (*)(void *)) session_info_timeout,
169 (void *) (long) info->id);
171 info->ses = ses;
172 info->task = task;
173 info->cache_mode = cache_mode;
175 if (uri) info->uri = get_uri_reference(uri);
176 if (referrer) info->referrer = get_uri_reference(referrer);
178 add_to_list(session_info, info);
180 return info->id;
183 static struct session *
184 init_saved_session(struct terminal *term, int id)
186 struct session_info *info = get_session_info(id);
187 struct session *ses;
189 if (!info) return NULL;
191 ses = init_session(info->ses, term, info->uri, 0);
193 if (!ses) {
194 done_session_info(info);
195 return ses;
198 /* Only do the ses_goto()-thing for target=_blank. */
199 if (info->uri && info->task != TASK_NONE) {
200 /* The init_session() call would have started the download but
201 * not with the requested cache mode etc. so interrupt that
202 * download . */
203 abort_loading(ses, 1);
205 ses->reloadlevel = info->cache_mode;
206 set_session_referrer(ses, info->referrer);
207 ses_goto(ses, info->uri, NULL, NULL, info->cache_mode,
208 info->task, 0);
211 done_session_info(info);
213 return ses;
216 static struct session *
217 get_master_session(void)
219 struct session *ses;
221 foreach (ses, sessions)
222 if (ses->tab->term->master) {
223 struct window *current_tab = get_current_tab(ses->tab->term);
225 return current_tab ? current_tab->data : NULL;
228 return NULL;
231 /** @relates session */
232 struct download *
233 get_current_download(struct session *ses)
235 struct download *download = NULL;
237 if (!ses) return NULL;
239 if (ses->task.type)
240 download = &ses->loading;
241 else if (have_location(ses))
242 download = &cur_loc(ses)->download;
244 if (download && is_in_state(download->state, S_OK)) {
245 struct file_to_load *ftl;
247 foreach (ftl, ses->more_files)
248 if (file_to_load_is_active(ftl))
249 return &ftl->download;
252 /* Note that @download isn't necessarily NULL here,
253 * if @ses->more_files is empty. -- Miciah */
254 return download;
257 void
258 print_error_dialog(struct session *ses, struct connection_state state,
259 struct uri *uri, enum connection_priority priority)
261 struct string msg;
262 unsigned char *uristring;
264 /* Don't show error dialogs for missing CSS stylesheets */
265 if (priority == PRI_CSS
266 || !init_string(&msg))
267 return;
269 uristring = uri ? get_uri_string(uri, URI_PUBLIC) : NULL;
270 if (uristring) {
271 #ifdef CONFIG_UTF8
272 if (ses->tab->term->utf8_cp)
273 decode_uri(uristring);
274 else
275 #endif /* CONFIG_UTF8 */
276 decode_uri_for_display(uristring);
277 add_format_to_string(&msg,
278 _("Unable to retrieve %s", ses->tab->term),
279 uristring);
280 mem_free(uristring);
281 add_to_string(&msg, ":\n\n");
284 add_to_string(&msg, get_state_message(state, ses->tab->term));
286 info_box(ses->tab->term, MSGBOX_FREE_TEXT,
287 N_("Error"), ALIGN_CENTER,
288 msg.source);
290 /* TODO: retry */
293 static void
294 abort_files_load(struct session *ses, int interrupt)
296 while (1) {
297 struct file_to_load *ftl;
298 int more = 0;
300 foreach (ftl, ses->more_files) {
301 if (!file_to_load_is_active(ftl))
302 continue;
304 more = 1;
305 cancel_download(&ftl->download, interrupt);
308 if (!more) break;
312 void
313 free_files(struct session *ses)
315 struct file_to_load *ftl;
317 abort_files_load(ses, 0);
318 foreach (ftl, ses->more_files) {
319 if (ftl->cached) object_unlock(ftl->cached);
320 if (ftl->uri) done_uri(ftl->uri);
321 mem_free_if(ftl->target_frame);
323 free_list(ses->more_files);
329 static void request_frameset(struct session *, struct frameset_desc *, int);
331 static void
332 request_frame(struct session *ses, unsigned char *name,
333 struct uri *uri, int depth)
335 struct location *loc = cur_loc(ses);
336 struct frame *frame;
338 assertm(have_location(ses), "request_frame: no location");
339 if_assert_failed return;
341 foreach (frame, loc->frames) {
342 struct document_view *doc_view;
344 if (c_strcasecmp(frame->name, name))
345 continue;
347 foreach (doc_view, ses->scrn_frames) {
348 if (doc_view->vs == &frame->vs && doc_view->document->frame_desc) {
349 request_frameset(ses, doc_view->document->frame_desc, depth);
350 return;
354 request_additional_file(ses, name, frame->vs.uri, PRI_FRAME);
355 return;
358 frame = mem_calloc(1, sizeof(*frame));
359 if (!frame) return;
361 frame->name = stracpy(name);
362 if (!frame->name) {
363 mem_free(frame);
364 return;
367 init_vs(&frame->vs, uri, -1);
369 add_to_list(loc->frames, frame);
371 request_additional_file(ses, name, frame->vs.uri, PRI_FRAME);
374 static void
375 request_frameset(struct session *ses, struct frameset_desc *frameset_desc, int depth)
377 int i;
379 if (depth > HTML_MAX_FRAME_DEPTH) return;
381 depth++; /* Inheritation counter (recursion brake ;) */
383 for (i = 0; i < frameset_desc->n; i++) {
384 struct frame_desc *frame_desc = &frameset_desc->frame_desc[i];
386 if (frame_desc->subframe) {
387 request_frameset(ses, frame_desc->subframe, depth);
388 } else if (frame_desc->name && frame_desc->uri) {
389 request_frame(ses, frame_desc->name,
390 frame_desc->uri, depth);
395 #ifdef CONFIG_CSS
396 static inline void
397 load_css_imports(struct session *ses, struct document_view *doc_view)
399 struct document *document = doc_view->document;
400 struct uri *uri;
401 int index;
403 if (!document) return;
405 foreach_uri (uri, index, &document->css_imports) {
406 request_additional_file(ses, "", uri, PRI_CSS);
409 #else
410 #define load_css_imports(ses, doc_view)
411 #endif
413 #ifdef CONFIG_ECMASCRIPT
414 static inline void
415 load_ecmascript_imports(struct session *ses, struct document_view *doc_view)
417 struct document *document = doc_view->document;
418 struct uri *uri;
419 int index;
421 if (!document) return;
423 foreach_uri (uri, index, &document->ecmascript_imports) {
424 request_additional_file(ses, "", uri, /* XXX */ PRI_CSS);
427 #else
428 #define load_ecmascript_imports(ses, doc_view)
429 #endif
431 inline void
432 load_frames(struct session *ses, struct document_view *doc_view)
434 struct document *document = doc_view->document;
436 if (!document || !document->frame_desc) return;
437 request_frameset(ses, document->frame_desc, 0);
439 foreach (doc_view, ses->scrn_frames) {
440 load_css_imports(ses, doc_view);
441 load_ecmascript_imports(ses, doc_view);
445 /** Timer callback for session.display_timer. As explained in install_timer(),
446 * this function must erase the expired timer ID from all variables. */
447 void
448 display_timer(struct session *ses)
450 timeval_T start, stop, duration;
451 milliseconds_T t;
453 timeval_now(&start);
454 draw_formatted(ses, 3);
455 timeval_now(&stop);
456 timeval_sub(&duration, &start, &stop);
458 t = mult_ms(timeval_to_milliseconds(&duration), DISPLAY_TIME);
459 if (t < DISPLAY_TIME_MIN) t = DISPLAY_TIME_MIN;
460 install_timer(&ses->display_timer, t,
461 (void (*)(void *)) display_timer,
462 ses);
463 /* The expired timer ID has now been erased. */
465 load_frames(ses, ses->doc_view);
466 load_css_imports(ses, ses->doc_view);
467 load_ecmascript_imports(ses, ses->doc_view);
468 process_file_requests(ses);
472 struct questions_entry {
473 LIST_HEAD(struct questions_entry);
475 void (*callback)(struct session *, void *);
476 void *data;
479 INIT_LIST_OF(struct questions_entry, questions_queue);
482 void
483 check_questions_queue(struct session *ses)
485 while (!list_empty(questions_queue)) {
486 struct questions_entry *q = questions_queue.next;
488 q->callback(ses, q->data);
489 del_from_list(q);
490 mem_free(q);
494 void
495 add_questions_entry(void (*callback)(struct session *, void *), void *data)
497 struct questions_entry *q = mem_alloc(sizeof(*q));
499 if (!q) return;
501 q->callback = callback;
502 q->data = data;
503 add_to_list(questions_queue, q);
506 #ifdef CONFIG_SCRIPTING
507 static void
508 maybe_pre_format_html(struct cache_entry *cached, struct session *ses)
510 struct fragment *fragment;
511 static int pre_format_html_event = EVENT_NONE;
513 if (!cached || cached->preformatted)
514 return;
516 /* The script called from here may indirectly call
517 * garbage_collection(). If the refcount of the cache entry
518 * were 0, it could then be freed, and the
519 * cached->preformatted assignment at the end of this function
520 * would crash. Normally, the document has a reference to the
521 * cache entry, and that suffices. However, if the cache
522 * entry was loaded to satisfy e.g. USEMAP="imgmap.html#map",
523 * then cached->object.refcount == 0 here, and must be
524 * incremented.
526 * cached->object.refcount == 0 is safe while the cache entry
527 * is being loaded, because garbage_collection() calls
528 * is_entry_used(), which checks whether any connection is
529 * using the cache entry. But loading has ended before this
530 * point. */
531 object_lock(cached);
533 fragment = get_cache_fragment(cached);
534 if (!fragment) goto unlock_and_return;
536 /* We cannot do anything if the data are fragmented. */
537 if (!list_is_singleton(cached->frag)) goto unlock_and_return;
539 set_event_id(pre_format_html_event, "pre-format-html");
540 trigger_event(pre_format_html_event, ses, cached);
542 /* XXX: Keep this after the trigger_event, because hooks might call
543 * normalize_cache_entry()! */
544 cached->preformatted = 1;
546 unlock_and_return:
547 object_unlock(cached);
549 #endif
551 static int
552 check_incomplete_redirects(struct cache_entry *cached)
554 assert(cached);
556 cached = follow_cached_redirects(cached);
557 if (cached && !cached->redirect) {
558 /* XXX: This is not quite true, but does that difference
559 * matter here? */
560 return cached->incomplete;
563 return 0;
567 session_is_loading(struct session *ses)
569 struct download *download = get_current_download(ses);
571 if (!download) return 0;
573 if (!is_in_result_state(download->state))
574 return 1;
576 /* The validness of download->cached (especially the download struct in
577 * ses->loading) is hard to maintain so check before using it.
578 * Related to bug 559. */
579 if (download->cached
580 && cache_entry_is_valid(download->cached)
581 && check_incomplete_redirects(download->cached))
582 return 1;
584 return 0;
587 void
588 doc_loading_callback(struct download *download, struct session *ses)
590 int submit = 0;
592 if (is_in_result_state(download->state)) {
593 #ifdef CONFIG_SCRIPTING
594 maybe_pre_format_html(download->cached, ses);
595 #endif
596 kill_timer(&ses->display_timer);
598 draw_formatted(ses, 1);
600 if (get_cmd_opt_bool("auto-submit")) {
601 if (!list_empty(ses->doc_view->document->forms)) {
602 get_cmd_opt_bool("auto-submit") = 0;
603 submit = 1;
607 load_frames(ses, ses->doc_view);
608 load_css_imports(ses, ses->doc_view);
609 load_ecmascript_imports(ses, ses->doc_view);
610 process_file_requests(ses);
612 start_document_refreshes(ses);
614 if (!is_in_state(download->state, S_OK)) {
615 print_error_dialog(ses, download->state,
616 ses->doc_view->document->uri,
617 download->pri);
620 } else if (is_in_transfering_state(download->state)
621 && ses->display_timer == TIMER_ID_UNDEF) {
622 display_timer(ses);
625 check_questions_queue(ses);
626 print_screen_status(ses);
628 #ifdef CONFIG_GLOBHIST
629 if (download->pri != PRI_CSS) {
630 unsigned char *title = ses->doc_view->document->title;
631 struct uri *uri;
633 if (download->conn)
634 uri = download->conn->proxied_uri;
635 else if (download->cached)
636 uri = download->cached->uri;
637 else
638 uri = NULL;
640 if (uri)
641 add_global_history_item(struri(uri), title, time(NULL));
643 #endif
645 if (submit) auto_submit_form(ses);
648 static void
649 file_loading_callback(struct download *download, struct file_to_load *ftl)
651 if (ftl->download.cached && ftl->cached != ftl->download.cached) {
652 if (ftl->cached) object_unlock(ftl->cached);
653 ftl->cached = ftl->download.cached;
654 object_lock(ftl->cached);
657 /* FIXME: We need to do content-type check here! However, we won't
658 * handle properly the "Choose action" dialog now :(. */
659 if (ftl->cached && !ftl->cached->redirect_get && download->pri != PRI_CSS) {
660 struct session *ses = ftl->ses;
661 struct uri *loading_uri = ses->loading_uri;
662 unsigned char *target_frame = null_or_stracpy(ses->task.target.frame);
664 ses->loading_uri = ftl->uri;
665 mem_free_set(&ses->task.target.frame, null_or_stracpy(ftl->target_frame));
666 setup_download_handler(ses, &ftl->download, ftl->cached, 1);
667 ses->loading_uri = loading_uri;
668 mem_free_set(&ses->task.target.frame, target_frame);
671 doc_loading_callback(download, ftl->ses);
674 static struct file_to_load *
675 request_additional_file(struct session *ses, unsigned char *name, struct uri *uri, int pri)
677 struct file_to_load *ftl;
679 if (uri->protocol == PROTOCOL_UNKNOWN) {
680 return NULL;
683 /* XXX: We cannot run the external handler here, because
684 * request_additional_file() is called many times for a single URL
685 * (normally the foreach() right below catches them all). Anyway,
686 * having <frame src="mailto:foo"> would be just weird, wouldn't it?
687 * --pasky */
688 if (get_protocol_external_handler(ses->tab->term, uri)) {
689 return NULL;
692 foreach (ftl, ses->more_files) {
693 if (compare_uri(ftl->uri, uri, URI_BASE)) {
694 if (ftl->pri > pri) {
695 ftl->pri = pri;
696 move_download(&ftl->download, &ftl->download, pri);
698 return NULL;
702 ftl = mem_calloc(1, sizeof(*ftl));
703 if (!ftl) return NULL;
705 ftl->uri = get_uri_reference(uri);
706 ftl->target_frame = stracpy(name);
707 ftl->download.callback = (download_callback_T *) file_loading_callback;
708 ftl->download.data = ftl;
709 ftl->pri = pri;
710 ftl->ses = ses;
712 add_to_list(ses->more_files, ftl);
714 return ftl;
717 static void
718 load_additional_file(struct file_to_load *ftl, enum cache_mode cache_mode)
720 struct document_view *doc_view = current_frame(ftl->ses);
721 struct uri *referrer = doc_view && doc_view->document
722 ? doc_view->document->uri : NULL;
724 load_uri(ftl->uri, referrer, &ftl->download, ftl->pri, cache_mode, -1);
727 void
728 process_file_requests(struct session *ses)
730 if (ses->status.processing_file_requests) return;
731 ses->status.processing_file_requests = 1;
733 while (1) {
734 struct file_to_load *ftl;
735 int more = 0;
737 foreach (ftl, ses->more_files) {
738 if (ftl->req_sent)
739 continue;
741 ftl->req_sent = 1;
743 load_additional_file(ftl, CACHE_MODE_NORMAL);
744 more = 1;
747 if (!more) break;
750 ses->status.processing_file_requests = 0;
754 static void
755 dialog_goto_url_open(void *data)
757 dialog_goto_url((struct session *) data, NULL);
760 /** @returns 0 if the first session was not properly initialized and
761 * setup_session() should be called on the session as well. */
762 static int
763 setup_first_session(struct session *ses, struct uri *uri)
765 /* [gettext_accelerator_context(setup_first_session)] */
766 struct terminal *term = ses->tab->term;
768 if (!*get_opt_str("protocol.http.user_agent", NULL)) {
769 info_box(term, 0,
770 N_("Warning"), ALIGN_CENTER,
771 N_("You have an empty string in protocol.http.user_agent - "
772 "this was a default value in the past, substituted by "
773 "default ELinks User-Agent string. However, currently "
774 "this means that NO User-Agent HEADER "
775 "WILL BE SENT AT ALL - if this is really what you want, "
776 "set its value to \" \", otherwise please delete the line "
777 "with this setting from your configuration file (if you "
778 "have no idea what I'm talking about, just do this), so "
779 "that the correct default setting will be used. Apologies for "
780 "any inconvience caused."));
783 if (!get_opt_bool("config.saving_style_w", NULL)) {
784 struct option *opt = get_opt_rec(config_options, "config.saving_style_w");
785 opt->value.number = 1;
786 option_changed(ses, opt);
787 if (get_opt_int("config.saving_style", NULL) != 3) {
788 info_box(term, 0,
789 N_("Warning"), ALIGN_CENTER,
790 N_("You have option config.saving_style set to "
791 "a de facto obsolete value. The configuration "
792 "saving algorithms of ELinks were changed from "
793 "the last time you upgraded ELinks. Now, only "
794 "those options which you actually changed are "
795 "saved to the configuration file, instead of "
796 "all the options. This simplifies our "
797 "situation greatly when we see that some option "
798 "has an inappropriate default value or we need to "
799 "change the semantics of some option in a subtle way. "
800 "Thus, we recommend you change the value of "
801 "config.saving_style option to 3 in order to get "
802 "the \"right\" behaviour. Apologies for any "
803 "inconvience caused."));
807 if (first_use) {
808 /* Only open the goto URL dialog if no URI was passed on the
809 * command line. */
810 void *handler = uri ? NULL : dialog_goto_url_open;
812 first_use = 0;
814 msg_box(term, NULL, 0,
815 N_("Welcome"), ALIGN_CENTER,
816 N_("Welcome to ELinks!\n\n"
817 "Press ESC for menu. Documentation is available in "
818 "Help menu."),
819 ses, 1,
820 MSG_BOX_BUTTON(N_("~OK"), handler, B_ENTER | B_ESC));
822 /* If there is no URI the goto dialog will pop up so there is
823 * no need to call setup_session(). */
824 if (!uri) return 1;
826 #ifdef CONFIG_BOOKMARKS
827 } else if (!uri && get_opt_bool("ui.sessions.auto_restore", NULL)) {
828 unsigned char *folder;
830 folder = get_opt_str("ui.sessions.auto_save_foldername", NULL);
831 open_bookmark_folder(ses, folder);
832 return 1;
833 #endif
836 /* If there's a URI to load we have to call */
837 return 0;
840 /** First load the current URI of the base session. In most cases it will just
841 * be fetched from the cache so that the new tab will not appear ``empty' while
842 * loading the real URI or showing the goto URL dialog. */
843 static void
844 setup_session(struct session *ses, struct uri *uri, struct session *base)
846 if (base && have_location(base)) {
847 struct location *loc = mem_calloc(1, sizeof(*loc));
849 if (loc) {
850 loc->download.state = connection_state(S_OK);
851 copy_location(loc, cur_loc(base));
852 add_to_history(&ses->history, loc);
853 render_document_frames(ses, 0);
857 if (uri) {
858 goto_uri(ses, uri);
860 } else if (!goto_url_home(ses)) {
861 if (get_opt_bool("ui.startup_goto_dialog", NULL)) {
862 dialog_goto_url_open(ses);
867 /** @relates session */
868 struct session *
869 init_session(struct session *base_session, struct terminal *term,
870 struct uri *uri, int in_background)
872 struct session *ses = mem_calloc(1, sizeof(*ses));
874 if (!ses) return NULL;
876 ses->tab = init_tab(term, ses, tabwin_func);
877 if (!ses->tab) {
878 mem_free(ses);
879 return NULL;
882 ses->option = copy_option(config_options,
883 CO_SHALLOW | CO_NO_LISTBOX_ITEM);
884 create_history(&ses->history);
885 init_list(ses->scrn_frames);
886 init_list(ses->more_files);
887 init_list(ses->type_queries);
888 ses->task.type = TASK_NONE;
889 ses->display_timer = TIMER_ID_UNDEF;
891 #ifdef CONFIG_LEDS
892 init_led_panel(&ses->status.leds);
893 ses->status.ssl_led = register_led(ses, 0);
894 ses->status.insert_mode_led = register_led(ses, 1);
895 ses->status.ecmascript_led = register_led(ses, 2);
896 ses->status.popup_led = register_led(ses, 3);
898 ses->status.download_led = register_led(ses, 5);
899 #endif
900 ses->status.force_show_status_bar = -1;
901 ses->status.force_show_title_bar = -1;
903 add_to_list(sessions, ses);
905 /* Update the status -- most importantly the info about whether to the
906 * show the title, tab and status bar -- _before_ loading the URI so
907 * the document cache is not filled with useless documents if the
908 * content is already cached.
910 * For big document it also reduces memory usage quite a bit because
911 * (atleast that is my interpretation --jonas) the old document will
912 * have a chance to be released before rendering a new one. A few
913 * numbers when opening a new tab while viewing debians package list
914 * for unstable:
916 * 9307 jonas 15 0 34252 30m 5088 S 0.0 12.2 0:03.63 elinks-old
917 * 9305 jonas 15 0 17060 13m 5088 S 0.0 5.5 0:02.07 elinks-new
919 update_status();
921 /* Check if the newly inserted session is the only in the list and do
922 * the special setup for the first session, */
923 if (!list_is_singleton(sessions) || !setup_first_session(ses, uri)) {
924 setup_session(ses, uri, base_session);
927 if (!in_background)
928 switch_to_tab(term, get_tab_number(ses->tab), -1);
930 if (!term->main_menu) activate_bfu_technology(ses, -1);
931 return ses;
934 static void
935 init_remote_session(struct session *ses, enum remote_session_flags *remote_ptr,
936 struct uri *uri)
938 enum remote_session_flags remote = *remote_ptr;
940 if (remote & SES_REMOTE_CURRENT_TAB) {
941 goto_uri(ses, uri);
942 /* Mask out the current tab flag */
943 *remote_ptr = remote & ~SES_REMOTE_CURRENT_TAB;
945 /* Remote session was masked out. Open all following URIs in
946 * new tabs, */
947 if (!*remote_ptr)
948 *remote_ptr = SES_REMOTE_NEW_TAB;
950 } else if (remote & SES_REMOTE_NEW_TAB) {
951 /* FIXME: This is not perfect. Doing multiple -remote
952 * with no URLs will make the goto dialogs
953 * inaccessible. Maybe we should not support this kind
954 * of thing or make the window focus detecting code
955 * more intelligent. --jonas */
956 open_uri_in_new_tab(ses, uri, 0, 0);
958 if (remote & SES_REMOTE_PROMPT_URL) {
959 dialog_goto_url_open(ses);
962 } else if (remote & SES_REMOTE_NEW_WINDOW) {
963 /* FIXME: It is quite rude because we just take the first
964 * possibility and should maybe make it possible to specify
965 * new-screen etc via -remote "openURL(..., new-*)" --jonas */
966 if (!can_open_in_new(ses->tab->term))
967 return;
969 open_uri_in_new_window(ses, uri, NULL,
970 ses->tab->term->environment,
971 CACHE_MODE_NORMAL, TASK_NONE);
973 } else if (remote & SES_REMOTE_ADD_BOOKMARK) {
974 #ifdef CONFIG_BOOKMARKS
975 if (!uri) return;
976 add_bookmark(NULL, 1, struri(uri), struri(uri));
977 #endif
979 } else if (remote & SES_REMOTE_INFO_BOX) {
980 unsigned char *text;
982 if (!uri) return;
984 text = memacpy(uri->data, uri->datalen);
985 if (!text) return;
987 info_box(ses->tab->term, MSGBOX_FREE_TEXT,
988 N_("Error"), ALIGN_CENTER,
989 text);
991 } else if (remote & SES_REMOTE_PROMPT_URL) {
992 dialog_goto_url_open(ses);
998 struct string *
999 encode_session_info(struct string *info,
1000 LIST_OF(struct string_list_item) *url_list)
1002 struct string_list_item *url;
1004 if (!init_string(info)) return NULL;
1006 foreach (url, *url_list) {
1007 struct string *str = &url->string;
1009 add_bytes_to_string(info, str->source, str->length + 1);
1012 return info;
1015 /** Older elinks versions (up to and including 0.9.1) sends no magic variable and if
1016 * this is detected we fallback to the old session info format. For this format
1017 * the magic member of terminal_info hold the length of the URI string. The
1018 * old format is handled by the default label in the switch.
1020 * The new session info format supports extraction of multiple URIS from the
1021 * terminal_info data member. The magic variable controls how to interpret
1022 * the fields:
1024 * - INTERLINK_NORMAL_MAGIC means use the terminal_info session_info
1025 * variable as an id for a saved session.
1027 * - INTERLINK_REMOTE_MAGIC means use the terminal_info session_info
1028 * variable as the remote session flags. */
1030 decode_session_info(struct terminal *term, struct terminal_info *info)
1032 int len = info->length;
1033 struct session *base_session = NULL;
1034 enum remote_session_flags remote = 0;
1035 unsigned char *str;
1037 switch (info->magic) {
1038 case INTERLINK_NORMAL_MAGIC:
1039 /* Lookup if there are any saved sessions that should be
1040 * resumed using the session_info as an id. The id is derived
1041 * from the value of -base-session command line option in the
1042 * connecting instance.
1044 * At the moment it is only used when opening instances in new
1045 * window to figure out how to initialize it when the new
1046 * instance connects to the master.
1048 * We don't need to handle it for the old format since new
1049 * instances connecting this way will always be of the same
1050 * origin as the master. */
1051 if (init_saved_session(term, info->session_info))
1052 return 1;
1053 break;
1055 case INTERLINK_REMOTE_MAGIC:
1056 /* This could mean some fatal bug but I am unsure if we can
1057 * actually assert it since people could pour all kinds of crap
1058 * down the socket. */
1059 if (!info->session_info) {
1060 INTERNAL("Remote magic with no remote flags");
1061 return 0;
1064 remote = info->session_info;
1066 /* If processing session info from a -remote instance we want
1067 * to hook up with the master so we can handle request for
1068 * stuff in current tab. */
1069 base_session = get_master_session();
1070 if (!base_session) return 0;
1072 break;
1074 default:
1075 /* The old format calculates the session_info and magic members
1076 * as part of the data that should be decoded so we have to
1077 * substract it to get the size of the actual URI data. */
1078 len -= sizeof(info->session_info) + sizeof(info->magic);
1080 /* Extract URI containing @magic bytes */
1081 if (info->magic <= 0 || info->magic > len)
1082 len = 0;
1083 else
1084 len = info->magic;
1087 if (len <= 0) {
1088 if (!remote)
1089 return !!init_session(base_session, term, NULL, 0);
1091 /* Even though there are no URIs we still have to
1092 * handle remote stuff. */
1093 init_remote_session(base_session, &remote, NULL);
1094 return 0;
1097 str = info->data;
1099 /* Extract multiple (possible) NUL terminated URIs */
1100 while (len > 0) {
1101 unsigned char *end = memchr(str, 0, len);
1102 int urilength = end ? end - str : len;
1103 struct uri *uri = NULL;
1104 unsigned char *uristring = memacpy(str, urilength);
1106 if (uristring) {
1107 uri = get_hooked_uri(uristring, base_session, term->cwd);
1108 mem_free(uristring);
1111 len -= urilength + 1;
1112 str += urilength + 1;
1114 if (remote) {
1115 if (!uri) continue;
1117 init_remote_session(base_session, &remote, uri);
1119 } else {
1120 int backgrounded = !list_empty(term->windows);
1121 int bad_url = !uri;
1122 struct session *ses;
1124 if (!uri)
1125 uri = get_uri("about:blank", 0);
1127 ses = init_session(base_session, term, uri, backgrounded);
1128 if (!ses) {
1129 /* End loop if initialization fails */
1130 len = 0;
1131 } else if (bad_url) {
1132 print_error_dialog(ses, connection_state(S_BAD_URL),
1133 NULL, PRI_MAIN);
1138 if (uri) done_uri(uri);
1141 /* If we only initialized remote sessions or didn't manage to add any
1142 * new tabs return zero so the terminal will be destroyed ASAP. */
1143 return remote ? 0 : !list_empty(term->windows);
1147 void
1148 abort_loading(struct session *ses, int interrupt)
1150 if (have_location(ses)) {
1151 struct location *loc = cur_loc(ses);
1153 cancel_download(&loc->download, interrupt);
1154 abort_files_load(ses, interrupt);
1156 abort_preloading(ses, interrupt);
1159 static void
1160 destroy_session(struct session *ses)
1162 struct document_view *doc_view;
1164 assert(ses);
1165 if_assert_failed return;
1167 destroy_downloads(ses);
1168 abort_loading(ses, 0);
1169 free_files(ses);
1170 if (ses->doc_view) {
1171 detach_formatted(ses->doc_view);
1172 mem_free(ses->doc_view);
1175 foreach (doc_view, ses->scrn_frames)
1176 detach_formatted(doc_view);
1178 free_list(ses->scrn_frames);
1180 destroy_history(&ses->history);
1181 set_session_referrer(ses, NULL);
1183 if (ses->loading_uri) done_uri(ses->loading_uri);
1185 kill_timer(&ses->display_timer);
1187 while (!list_empty(ses->type_queries))
1188 done_type_query(ses->type_queries.next);
1190 if (ses->download_uri) done_uri(ses->download_uri);
1191 mem_free_if(ses->search_word);
1192 mem_free_if(ses->last_search_word);
1193 mem_free_if(ses->status.last_title);
1194 #ifdef CONFIG_ECMASCRIPT
1195 mem_free_if(ses->status.window_status);
1196 #endif
1197 if (ses->option) {
1198 delete_option(ses->option);
1199 ses->option = NULL;
1201 del_from_list(ses);
1204 void
1205 reload(struct session *ses, enum cache_mode cache_mode)
1207 reload_frame(ses, NULL, cache_mode);
1210 void
1211 reload_frame(struct session *ses, unsigned char *name,
1212 enum cache_mode cache_mode)
1214 abort_loading(ses, 0);
1216 if (cache_mode == CACHE_MODE_INCREMENT) {
1217 cache_mode = CACHE_MODE_NEVER;
1218 if (ses->reloadlevel < CACHE_MODE_NEVER)
1219 cache_mode = ++ses->reloadlevel;
1220 } else {
1221 ses->reloadlevel = cache_mode;
1224 if (have_location(ses)) {
1225 struct location *loc = cur_loc(ses);
1226 struct file_to_load *ftl;
1228 #ifdef CONFIG_ECMASCRIPT
1229 loc->vs.ecmascript_fragile = 1;
1230 #endif
1232 /* FIXME: When reloading use loading_callback and set up a
1233 * session task so that the reloading will work even when the
1234 * reloaded document contains redirects. This is needed atleast
1235 * when reloading HTTP auth document after the user has entered
1236 * credentials. */
1237 loc->download.data = ses;
1238 loc->download.callback = (download_callback_T *) doc_loading_callback;
1240 mem_free_set(&ses->task.target.frame, null_or_stracpy(name));
1242 load_uri(loc->vs.uri, ses->referrer, &loc->download, PRI_MAIN, cache_mode, -1);
1244 foreach (ftl, ses->more_files) {
1245 if (file_to_load_is_active(ftl))
1246 continue;
1248 ftl->download.data = ftl;
1249 ftl->download.callback = (download_callback_T *) file_loading_callback;
1251 load_additional_file(ftl, cache_mode);
1257 struct frame *
1258 ses_find_frame(struct session *ses, unsigned char *name)
1260 struct location *loc = cur_loc(ses);
1261 struct frame *frame;
1263 assertm(have_location(ses), "ses_request_frame: no location yet");
1264 if_assert_failed return NULL;
1266 foreachback (frame, loc->frames)
1267 if (!c_strcasecmp(frame->name, name))
1268 return frame;
1270 return NULL;
1273 void
1274 set_session_referrer(struct session *ses, struct uri *referrer)
1276 if (ses->referrer) done_uri(ses->referrer);
1277 ses->referrer = referrer ? get_uri_reference(referrer) : NULL;
1280 static void
1281 tabwin_func(struct window *tab, struct term_event *ev)
1283 struct session *ses = tab->data;
1285 switch (ev->ev) {
1286 case EVENT_ABORT:
1287 if (ses) destroy_session(ses);
1288 if (!list_empty(sessions)) update_status();
1289 break;
1290 case EVENT_INIT:
1291 case EVENT_RESIZE:
1292 tab->resize = 1;
1293 /* fall-through */
1294 case EVENT_REDRAW:
1295 if (!ses || ses->tab != get_current_tab(ses->tab->term))
1296 break;
1298 draw_formatted(ses, tab->resize);
1299 if (tab->resize) {
1300 load_frames(ses, ses->doc_view);
1301 process_file_requests(ses);
1302 tab->resize = 0;
1304 print_screen_status(ses);
1305 break;
1306 case EVENT_KBD:
1307 case EVENT_MOUSE:
1308 if (!ses) break;
1309 /* This check is related to bug 296 */
1310 assert(ses->tab == get_current_tab(ses->tab->term));
1311 send_event(ses, ev);
1312 break;
1317 * Gets the url being viewed by this session. Writes it into @a str.
1318 * A maximum of @a str_size bytes (including null) will be written.
1319 * @relates session
1321 unsigned char *
1322 get_current_url(struct session *ses, unsigned char *str, size_t str_size)
1324 struct uri *uri;
1325 int length;
1327 assert(str && str_size > 0);
1329 uri = have_location(ses) ? cur_loc(ses)->vs.uri : ses->loading_uri;
1331 /* Not looking or loading anything */
1332 if (!uri) return NULL;
1334 /* Ensure that the url size is not greater than str_size.
1335 * We can't just happily strncpy(str, here, str_size)
1336 * because we have to stop at POST_CHAR, not only at NULL. */
1337 length = int_min(get_real_uri_length(uri), str_size - 1);
1339 return safe_strncpy(str, struri(uri), length + 1);
1343 * Gets the title of the page being viewed by this session. Writes it into
1344 * @a str. A maximum of @a str_size bytes (including null) will be written.
1345 * @relates session
1347 unsigned char *
1348 get_current_title(struct session *ses, unsigned char *str, size_t str_size)
1350 struct document_view *doc_view = current_frame(ses);
1352 assert(str && str_size > 0);
1354 /* Ensure that the title is defined */
1355 /* TODO: Try globhist --jonas */
1356 if (doc_view && doc_view->document->title)
1357 return safe_strncpy(str, doc_view->document->title, str_size);
1359 return NULL;
1363 * Gets the url of the link currently selected. Writes it into @a str.
1364 * A maximum of @a str_size bytes (including null) will be written.
1365 * @relates session
1367 unsigned char *
1368 get_current_link_url(struct session *ses, unsigned char *str, size_t str_size)
1370 struct link *link = get_current_session_link(ses);
1372 assert(str && str_size > 0);
1374 if (!link) return NULL;
1376 return safe_strncpy(str, link->where ? link->where : link->where_img, str_size);
1379 /** get_current_link_name: returns the name of the current link
1380 * (the text between @<A> and @</A>), @a str is a preallocated string,
1381 * @a str_size includes the null char.
1382 * @relates session */
1383 unsigned char *
1384 get_current_link_name(struct session *ses, unsigned char *str, size_t str_size)
1386 struct link *link = get_current_session_link(ses);
1387 unsigned char *where, *name = NULL;
1389 assert(str && str_size > 0);
1391 if (!link) return NULL;
1393 where = link->where ? link->where : link->where_img;
1394 #ifdef CONFIG_GLOBHIST
1396 struct global_history_item *item;
1398 item = get_global_history_item(where);
1399 if (item) name = item->title;
1401 #endif
1402 if (!name) name = get_link_name(link);
1403 if (!name) name = where;
1405 return safe_strncpy(str, name, str_size);
1408 struct link *
1409 get_current_link_in_view(struct document_view *doc_view)
1411 struct link *link = get_current_link(doc_view);
1413 return link && !link_is_form(link) ? link : NULL;
1416 /** @relates session */
1417 struct link *
1418 get_current_session_link(struct session *ses)
1420 return get_current_link_in_view(current_frame(ses));
1423 /** @relates session */
1425 eat_kbd_repeat_count(struct session *ses)
1427 int count = ses->kbdprefix.repeat_count;
1429 ses->kbdprefix.repeat_count = 0;
1431 /* Clear status bar when prefix is eaten (bug 930) */
1432 print_screen_status(ses);
1433 return count;