12 #include "bfu/dialog.h"
15 #include "config/options.h"
16 #include "config/urlhist.h"
17 #include "document/document.h"
18 #include "document/view.h"
19 #include "dialogs/exmode.h"
20 #include "dialogs/info.h"
21 #include "dialogs/menu.h"
22 #include "dialogs/options.h"
23 #include "intl/gettext/libintl.h"
24 #include "main/event.h"
25 #include "main/main.h"
26 #include "main/select.h"
27 #include "mime/dialogs.h"
28 #include "mime/mime.h"
29 #include "network/connection.h"
30 #include "osdep/osdep.h"
31 #include "osdep/newwin.h"
32 #include "protocol/protocol.h"
33 #include "protocol/uri.h"
34 #include "session/download.h"
35 #include "session/history.h"
36 #include "session/location.h"
37 #include "session/session.h"
38 #include "session/task.h"
39 #include "terminal/tab.h"
40 #include "terminal/terminal.h"
41 #include "util/conv.h"
42 #include "util/file.h"
43 #include "util/memlist.h"
44 #include "util/memory.h"
45 #include "util/string.h"
46 #include "viewer/action.h"
47 #include "viewer/text/link.h"
48 #include "viewer/text/view.h"
51 /* Helper for url items in help menu. */
53 menu_url_shortcut(struct terminal
*term
, void *url_
, void *ses_
)
55 unsigned char *url
= url_
;
56 struct session
*ses
= ses_
;
57 struct uri
*uri
= get_uri(url
, 0);
65 save_url(struct session
*ses
, unsigned char *url
)
67 struct document_view
*doc_view
;
70 assert(ses
&& ses
->tab
&& ses
->tab
->term
&& url
);
71 if_assert_failed
return;
75 uri
= get_translated_uri(url
, ses
->tab
->term
->cwd
);
77 print_error_dialog(ses
, S_BAD_URL
, uri
, PRI_CANCEL
);
81 if (ses
->download_uri
) done_uri(ses
->download_uri
);
82 ses
->download_uri
= uri
;
84 doc_view
= current_frame(ses
);
85 assert(doc_view
&& doc_view
->document
&& doc_view
->document
->uri
);
86 if_assert_failed
return;
88 set_session_referrer(ses
, doc_view
->document
->uri
);
89 query_file(ses
, ses
->download_uri
, ses
, start_download
, NULL
, 1);
93 save_url_as(struct session
*ses
)
95 input_dialog(ses
->tab
->term
, NULL
,
96 N_("Save URL"), N_("Enter URL"),
97 ses
, &goto_url_history
,
98 MAX_STR_LEN
, "", 0, 0, NULL
,
99 (void (*)(void *, unsigned char *)) save_url
,
104 really_exit_prog(void *ses_
)
106 struct session
*ses
= ses_
;
108 register_bottom_half(destroy_terminal
, ses
->tab
->term
);
112 dont_exit_prog(void *ses_
)
114 struct session
*ses
= ses_
;
120 query_exit(struct session
*ses
)
122 /* [gettext_accelerator_context(query_exit)] */
124 msg_box(ses
->tab
->term
, NULL
, 0,
125 N_("Exit ELinks"), ALIGN_CENTER
,
126 (ses
->tab
->term
->next
== ses
->tab
->term
->prev
&& are_there_downloads())
127 ? N_("Do you really want to exit ELinks "
128 "(and terminate all downloads)?")
129 : N_("Do you really want to exit ELinks?"),
131 MSG_BOX_BUTTON(N_("~Yes"), really_exit_prog
, B_ENTER
),
132 MSG_BOX_BUTTON(N_("~No"), dont_exit_prog
, B_ESC
));
136 exit_prog(struct session
*ses
, int query
)
140 /* An exit query is in progress. */
144 /* Force a query if the last terminal is exiting with downloads still in
146 if (query
|| (list_is_singleton(terminals
) && are_there_downloads())) {
151 really_exit_prog(ses
);
156 go_historywards(struct terminal
*term
, void *target_
, void *ses_
)
158 struct location
*target
= target_
;
159 struct session
*ses
= ses_
;
161 go_history(ses
, target
);
164 static struct menu_item no_hist_menu
[] = {
165 INIT_MENU_ITEM(N_("No history"), NULL
, ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
),
169 /* unhist == 0 => history
170 * unhist == 1 => unhistory */
172 history_menu_common(struct terminal
*term
, struct session
*ses
, int unhist
)
174 struct menu_item
*mi
= NULL
;
176 if (have_location(ses
)) {
177 struct location
*loc
;
179 for (loc
= unhist
? cur_loc(ses
)->next
: cur_loc(ses
)->prev
;
180 loc
!= (struct location
*) &ses
->history
.history
;
181 loc
= unhist
? loc
->next
: loc
->prev
) {
185 mi
= new_menu(FREE_LIST
| FREE_TEXT
| NO_INTL
);
189 url
= get_uri_string(loc
->vs
.uri
, URI_PUBLIC
);
191 add_to_menu(&mi
, url
, NULL
, ACT_MAIN_NONE
,
199 do_menu(term
, no_hist_menu
, ses
, 0);
201 do_menu(term
, mi
, ses
, 0);
205 history_menu(struct terminal
*term
, void *xxx
, void *ses_
)
207 struct session
*ses
= ses_
;
209 history_menu_common(term
, ses
, 0);
213 unhistory_menu(struct terminal
*term
, void *xxx
, void *ses_
)
215 struct session
*ses
= ses_
;
217 history_menu_common(term
, ses
, 1);
221 tab_menu(struct session
*ses
, int x
, int y
, int place_above_cursor
)
223 /* [gettext_accelerator_context(tab_menu)] */
224 struct menu_item
*menu
;
226 #ifdef CONFIG_BOOKMARKS
227 int anonymous
= get_cmd_opt_bool("anonymous");
230 assert(ses
&& ses
->tab
);
231 if_assert_failed
return;
233 tabs_count
= number_of_tabs(ses
->tab
->term
);
234 menu
= new_menu(FREE_LIST
);
237 add_menu_action(&menu
, N_("Go ~back"), ACT_MAIN_HISTORY_MOVE_BACK
);
238 add_menu_action(&menu
, N_("Go for~ward"), ACT_MAIN_HISTORY_MOVE_FORWARD
);
240 if (have_location(ses
)) {
241 add_menu_separator(&menu
);
243 #ifdef CONFIG_BOOKMARKS
245 add_menu_action(&menu
, N_("Bookm~ark document"), ACT_MAIN_ADD_BOOKMARK
);
249 add_menu_action(&menu
, N_("Toggle ~HTML/plain"), ACT_MAIN_TOGGLE_HTML_PLAIN
);
250 add_menu_action(&menu
, N_("~Reload"), ACT_MAIN_RELOAD
);
252 if (ses
->doc_view
&& document_has_frames(ses
->doc_view
->document
)) {
253 add_menu_action(&menu
, N_("Frame at ~full-screen"), ACT_MAIN_FRAME_MAXIMIZE
);
254 add_uri_command_to_menu(&menu
, PASS_URI_FRAME
,
255 N_("~Pass frame URI to external command"));
259 /* Keep tab related operations below this separator */
260 add_menu_separator(&menu
);
262 if (tabs_count
> 1) {
263 add_menu_action(&menu
, N_("Nex~t tab"), ACT_MAIN_TAB_NEXT
);
264 add_menu_action(&menu
, N_("Pre~v tab"), ACT_MAIN_TAB_PREV
);
267 add_menu_action(&menu
, N_("~Close tab"), ACT_MAIN_TAB_CLOSE
);
269 if (tabs_count
> 1) {
270 add_menu_action(&menu
, N_("C~lose all tabs but the current"),
271 ACT_MAIN_TAB_CLOSE_ALL_BUT_CURRENT
);
272 #ifdef CONFIG_BOOKMARKS
274 add_menu_action(&menu
, N_("B~ookmark all tabs"),
275 ACT_MAIN_ADD_BOOKMARK_TABS
);
280 if (have_location(ses
)) {
281 add_uri_command_to_menu(&menu
, PASS_URI_TAB
,
282 N_("Pass tab URI to e~xternal command"));
285 /* Adjust the menu position taking the menu frame into account */
286 if (place_above_cursor
) {
289 while (menu
[i
].text
) i
++;
291 y
= int_max(y
- i
- 1, 0);
294 set_window_ptr(ses
->tab
, x
, y
);
296 do_menu(ses
->tab
->term
, menu
, ses
, 1);
300 do_submenu(struct terminal
*term
, void *menu_
, void *ses_
)
302 struct menu_item
*menu
= menu_
;
304 do_menu(term
, menu
, ses_
, 1);
308 static struct menu_item file_menu11
[] = {
309 /* [gettext_accelerator_context(.file_menu)] */
310 INIT_MENU_ACTION(N_("Open new ~tab"), ACT_MAIN_OPEN_NEW_TAB
),
311 INIT_MENU_ACTION(N_("Open new tab in backgroun~d"), ACT_MAIN_OPEN_NEW_TAB_IN_BACKGROUND
),
312 INIT_MENU_ACTION(N_("~Go to URL"), ACT_MAIN_GOTO_URL
),
313 INIT_MENU_ACTION(N_("Go ~back"), ACT_MAIN_HISTORY_MOVE_BACK
),
314 INIT_MENU_ACTION(N_("Go ~forward"), ACT_MAIN_HISTORY_MOVE_FORWARD
),
315 INIT_MENU_ITEM(N_("~History"), NULL
, ACT_MAIN_NONE
, history_menu
, NULL
, SUBMENU
),
316 INIT_MENU_ITEM(N_("~Unhistory"), NULL
, ACT_MAIN_NONE
, unhistory_menu
, NULL
, SUBMENU
),
319 static struct menu_item file_menu21
[] = {
320 /* [gettext_accelerator_context(.file_menu)] */
322 INIT_MENU_ACTION(N_("~Save as"), ACT_MAIN_SAVE_AS
),
323 INIT_MENU_ACTION(N_("Save UR~L as"), ACT_MAIN_SAVE_URL_AS
),
324 INIT_MENU_ACTION(N_("Sa~ve formatted document"), ACT_MAIN_SAVE_FORMATTED
),
325 #ifdef CONFIG_BOOKMARKS
326 INIT_MENU_ACTION(N_("Bookm~ark document"), ACT_MAIN_ADD_BOOKMARK
),
330 static struct menu_item file_menu22
[] = {
331 /* [gettext_accelerator_context(.file_menu)] */
333 INIT_MENU_ACTION(N_("~Kill background connections"), ACT_MAIN_KILL_BACKGROUNDED_CONNECTIONS
),
334 INIT_MENU_ACTION(N_("Flush all ~caches"), ACT_MAIN_CACHE_MINIMIZE
),
335 INIT_MENU_ACTION(N_("Resource ~info"), ACT_MAIN_RESOURCE_INFO
),
339 static struct menu_item file_menu3
[] = {
340 /* [gettext_accelerator_context(.file_menu)] */
342 INIT_MENU_ACTION(N_("E~xit"), ACT_MAIN_QUIT
),
347 do_file_menu(struct terminal
*term
, void *xxx
, void *ses_
)
349 /* [gettext_accelerator_context(.file_menu)] */
350 struct menu_item
*file_menu
, *e
, *f
;
351 int anonymous
= get_cmd_opt_bool("anonymous");
354 file_menu
= mem_alloc(sizeof(file_menu11
) + sizeof(file_menu21
)
355 + sizeof(file_menu22
) + sizeof(file_menu3
)
356 + 3 * sizeof(struct menu_item
));
357 if (!file_menu
) return;
362 && !get_cmd_opt_bool("no-connect")
363 && !get_cmd_opt_bool("no-home"))
364 o
= can_open_in_new(term
);
369 SET_MENU_ITEM(e
, N_("Open ~new window"), NULL
, ACT_MAIN_OPEN_NEW_WINDOW
,
370 open_in_new_window
, send_open_new_window
,
371 (o
- 1) ? SUBMENU
: 0, HKS_SHOW
, 0);
375 memcpy(e
, file_menu11
, sizeof(file_menu11
));
376 e
+= sizeof_array(file_menu11
);
379 memcpy(e
, file_menu21
, sizeof(file_menu21
));
380 e
+= sizeof_array(file_menu21
);
383 memcpy(e
, file_menu22
, sizeof(file_menu22
));
384 e
+= sizeof_array(file_menu22
);
387 if (!anonymous
&& can_open_os_shell(term
->environment
)) {
388 SET_MENU_ITEM(e
, N_("~OS shell"), NULL
, ACT_MAIN_OPEN_OS_SHELL
,
389 NULL
, NULL
, 0, HKS_SHOW
, 0);
394 if (can_resize_window(term
->environment
)) {
395 SET_MENU_ITEM(e
, N_("Resize t~erminal"), NULL
, ACT_MAIN_TERMINAL_RESIZE
,
396 NULL
, NULL
, 0, HKS_SHOW
, 0);
401 memcpy(e
, file_menu3
+ x
, sizeof(file_menu3
) - x
* sizeof(struct menu_item
));
402 e
+= sizeof_array(file_menu3
);
404 for (f
= file_menu
; f
< e
; f
++)
405 f
->flags
|= FREE_LIST
;
407 do_menu(term
, file_menu
, ses_
, 1);
410 static struct menu_item view_menu
[] = {
411 /* [gettext_accelerator_context(.view_menu)] */
412 INIT_MENU_ACTION(N_("~Search"), ACT_MAIN_SEARCH
),
413 INIT_MENU_ACTION(N_("Search ~backward"), ACT_MAIN_SEARCH_BACK
),
414 INIT_MENU_ACTION(N_("Find ~next"), ACT_MAIN_FIND_NEXT
),
415 INIT_MENU_ACTION(N_("Find ~previous"), ACT_MAIN_FIND_NEXT_BACK
),
416 INIT_MENU_ACTION(N_("T~ypeahead search"), ACT_MAIN_SEARCH_TYPEAHEAD
),
418 INIT_MENU_ACTION(N_("Toggle ~HTML/plain"), ACT_MAIN_TOGGLE_HTML_PLAIN
),
419 INIT_MENU_ACTION(N_("Toggle i~mages"), ACT_MAIN_TOGGLE_DISPLAY_IMAGES
),
420 INIT_MENU_ACTION(N_("Toggle ~link numbering"), ACT_MAIN_TOGGLE_NUMBERED_LINKS
),
421 INIT_MENU_ACTION(N_("Toggle ~document colors"), ACT_MAIN_TOGGLE_DOCUMENT_COLORS
),
422 INIT_MENU_ACTION(N_("~Wrap text on/off"), ACT_MAIN_TOGGLE_WRAP_TEXT
),
424 INIT_MENU_ACTION(N_("Document ~info"), ACT_MAIN_DOCUMENT_INFO
),
425 INIT_MENU_ACTION(N_("H~eader info"), ACT_MAIN_HEADER_INFO
),
426 INIT_MENU_ACTION(N_("Rel~oad document"), ACT_MAIN_RELOAD
),
427 INIT_MENU_ACTION(N_("~Rerender document"), ACT_MAIN_RERENDER
),
428 INIT_MENU_ACTION(N_("Frame at ~full-screen"), ACT_MAIN_FRAME_MAXIMIZE
),
430 INIT_MENU_ACTION(N_("Nex~t tab"), ACT_MAIN_TAB_NEXT
),
431 INIT_MENU_ACTION(N_("Pre~v tab"), ACT_MAIN_TAB_PREV
),
432 INIT_MENU_ACTION(N_("~Close tab"), ACT_MAIN_TAB_CLOSE
),
437 static struct menu_item help_menu
[] = {
438 /* [gettext_accelerator_context(.help_menu)] */
439 INIT_MENU_ITEM(N_("~ELinks homepage"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_WEBSITE_URL
, 0),
440 INIT_MENU_ITEM(N_("~Documentation"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_DOC_URL
, 0),
441 INIT_MENU_ITEM(N_("~Keys"), NULL
, ACT_MAIN_NONE
, menu_keys
, NULL
, 0),
443 INIT_MENU_ITEM(N_("LED ~indicators"), NULL
, ACT_MAIN_NONE
, menu_leds_info
, NULL
, 0),
446 INIT_MENU_ITEM(N_("~Bugs information"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_BUGS_URL
, 0),
448 INIT_MENU_ITEM(N_("ELinks ~GITWeb"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_GITWEB_URL
, 0),
451 INIT_MENU_ITEM(N_("~Copying"), NULL
, ACT_MAIN_NONE
, menu_copying
, NULL
, 0),
452 INIT_MENU_ITEM(N_("Autho~rs"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_AUTHORS_URL
, 0),
453 INIT_MENU_ITEM(N_("~About"), NULL
, ACT_MAIN_NONE
, menu_about
, NULL
, 0),
458 static struct menu_item ext_menu
[] = {
459 /* [gettext_accelerator_context(.ext_menu)] */
460 INIT_MENU_ITEM(N_("~Add"), NULL
, ACT_MAIN_NONE
, menu_add_ext
, NULL
, 0),
461 INIT_MENU_ITEM(N_("~Modify"), NULL
, ACT_MAIN_NONE
, menu_list_ext
, menu_add_ext
, SUBMENU
),
462 INIT_MENU_ITEM(N_("~Delete"), NULL
, ACT_MAIN_NONE
, menu_list_ext
, menu_del_ext
, SUBMENU
),
466 static struct menu_item setup_menu
[] = {
467 /* [gettext_accelerator_context(.setup_menu)] */
469 INIT_MENU_ITEM(N_("~Language"), NULL
, ACT_MAIN_NONE
, menu_language_list
, NULL
, SUBMENU
),
471 INIT_MENU_ITEM(N_("C~haracter set"), NULL
, ACT_MAIN_NONE
, charset_list
, NULL
, SUBMENU
),
472 INIT_MENU_ACTION(N_("~Terminal options"), ACT_MAIN_SHOW_TERM_OPTIONS
),
473 INIT_MENU_ITEM(N_("File ~extensions"), NULL
, ACT_MAIN_NONE
, do_submenu
, ext_menu
, SUBMENU
),
475 INIT_MENU_ACTION(N_("~Options manager"), ACT_MAIN_OPTIONS_MANAGER
),
476 INIT_MENU_ACTION(N_("~Keybinding manager"), ACT_MAIN_KEYBINDING_MANAGER
),
477 INIT_MENU_ACTION(N_("~Save options"), ACT_MAIN_SAVE_OPTIONS
),
481 static struct menu_item setup_menu_anon
[] = {
482 /* [gettext_accelerator_context(.setup_menu)] */
483 INIT_MENU_ITEM(N_("~Language"), NULL
, ACT_MAIN_NONE
, menu_language_list
, NULL
, SUBMENU
),
484 INIT_MENU_ITEM(N_("C~haracter set"), NULL
, ACT_MAIN_NONE
, charset_list
, NULL
, SUBMENU
),
485 INIT_MENU_ACTION(N_("~Terminal options"), ACT_MAIN_SHOW_TERM_OPTIONS
),
489 static struct menu_item tools_menu
[] = {
490 /* [gettext_accelerator_context(.tools_menu)] */
491 #ifdef CONFIG_GLOBHIST
492 INIT_MENU_ACTION(N_("Global ~history"), ACT_MAIN_HISTORY_MANAGER
),
494 #ifdef CONFIG_BOOKMARKS
495 INIT_MENU_ACTION(N_("~Bookmarks"), ACT_MAIN_BOOKMARK_MANAGER
),
497 INIT_MENU_ACTION(N_("~Cache"), ACT_MAIN_CACHE_MANAGER
),
498 INIT_MENU_ACTION(N_("~Downloads"), ACT_MAIN_DOWNLOAD_MANAGER
),
499 #ifdef CONFIG_COOKIES
500 INIT_MENU_ACTION(N_("Coo~kies"), ACT_MAIN_COOKIE_MANAGER
),
502 #ifdef CONFIG_FORMHIST
503 INIT_MENU_ACTION(N_("~Form history"), ACT_MAIN_FORMHIST_MANAGER
),
505 INIT_MENU_ACTION(N_("~Authentication"), ACT_MAIN_AUTH_MANAGER
),
510 do_setup_menu(struct terminal
*term
, void *xxx
, void *ses_
)
512 struct session
*ses
= ses_
;
514 if (!get_cmd_opt_bool("anonymous"))
515 do_menu(term
, setup_menu
, ses
, 1);
517 do_menu(term
, setup_menu_anon
, ses
, 1);
520 static struct menu_item main_menu
[] = {
521 /* [gettext_accelerator_context(.main_menu)] */
522 INIT_MENU_ITEM(N_("~File"), NULL
, ACT_MAIN_NONE
, do_file_menu
, NULL
, FREE_LIST
| SUBMENU
),
523 INIT_MENU_ITEM(N_("~View"), NULL
, ACT_MAIN_NONE
, do_submenu
, view_menu
, FREE_LIST
| SUBMENU
),
524 INIT_MENU_ITEM(N_("~Link"), NULL
, ACT_MAIN_NONE
, link_menu
, NULL
, FREE_LIST
| SUBMENU
),
525 INIT_MENU_ITEM(N_("~Tools"), NULL
, ACT_MAIN_NONE
, do_submenu
, tools_menu
, FREE_LIST
| SUBMENU
),
526 INIT_MENU_ITEM(N_("~Setup"), NULL
, ACT_MAIN_NONE
, do_setup_menu
, NULL
, FREE_LIST
| SUBMENU
),
527 INIT_MENU_ITEM(N_("~Help"), NULL
, ACT_MAIN_NONE
, do_submenu
, help_menu
, FREE_LIST
| SUBMENU
),
532 activate_bfu_technology(struct session
*ses
, int item
)
534 do_mainmenu(ses
->tab
->term
, main_menu
, ses
, item
);
539 dialog_goto_url(struct session
*ses
, unsigned char *url
)
541 input_dialog(ses
->tab
->term
, NULL
,
542 N_("Go to URL"), N_("Enter URL"),
543 ses
, &goto_url_history
,
544 MAX_STR_LEN
, url
, 0, 0, NULL
,
545 (void (*)(void *, unsigned char *)) goto_url_with_hook
,
550 static INIT_INPUT_HISTORY(file_history
);
553 query_file(struct session
*ses
, struct uri
*uri
, void *data
,
554 void (*std
)(void *, unsigned char *),
555 void (*cancel
)(void *), int interactive
)
560 if_assert_failed
return;
562 /* FIXME: This ``sanity'' checking is mostly for the download code
563 * using this function. They pass ses->download_uri and we have to make
564 * sure that the connection code can download the URI. The reason we do
565 * it before is that then users won't waste time typing a filename and
566 * then discover that the URI can not be downloaded. However it might
567 * be better to introduce a set_session_download_uri() which will do
568 * the checking? --jonas */
570 if (uri
->protocol
== PROTOCOL_UNKNOWN
) {
571 print_error_dialog(ses
, S_UNKNOWN_PROTOCOL
, uri
, PRI_CANCEL
);
575 if (get_protocol_external_handler(ses
->tab
->term
, uri
)) {
576 print_error_dialog(ses
, S_EXTERNAL_PROTOCOL
, uri
, PRI_CANCEL
);
580 if (!init_string(&def
)) return;
582 add_to_string(&def
, get_opt_str("document.download.directory", NULL
));
583 if (def
.length
&& !dir_sep(def
.source
[def
.length
- 1]))
584 add_char_to_string(&def
, '/');
586 add_mime_filename_to_string(&def
, uri
);
588 /* Remove the %-ugliness for display */
590 if (ses
->tab
->term
->utf8_cp
)
591 decode_uri_string(&def
);
593 #endif /* CONFIG_UTF8 */
594 decode_uri_string_for_display(&def
);
597 input_dialog(ses
->tab
->term
, NULL
,
598 N_("Download"), N_("Save to file"),
600 MAX_STR_LEN
, def
.source
, 0, 0, check_nonempty
,
601 (void (*)(void *, unsigned char *)) std
,
602 (void (*)(void *)) cancel
);
604 std(data
, def
.source
);
611 free_history_lists(void)
613 free_list(file_history
.entries
);
614 #ifdef CONFIG_SCRIPTING
615 trigger_event_name("free-history");
621 add_cmdline_bool_option(struct string
*string
, unsigned char *name
)
623 if (!get_cmd_opt_bool(name
)) return;
624 add_to_string(string
, " -");
625 add_to_string(string
, name
);
629 open_uri_in_new_window(struct session
*ses
, struct uri
*uri
, struct uri
*referrer
,
630 enum term_env_type env
, enum cache_mode cache_mode
,
633 int ring
= get_cmd_opt_int("session-ring");
634 struct string parameters
;
638 if_assert_failed
return;
640 id
= add_session_info(ses
, uri
, referrer
, cache_mode
, task
);
643 if (!init_string(¶meters
)) return;
645 add_format_to_string(¶meters
, "-base-session %d", id
);
646 if (ring
) add_format_to_string(¶meters
, " -session-ring %d", ring
);
648 /* No URI means open new (clean) window possibly without connecting to
649 * the current master so add command line options to properly clone the
652 /* Adding -touch-files will only lead to problems */
653 add_cmdline_bool_option(¶meters
, "localhost");
654 add_cmdline_bool_option(¶meters
, "no-home");
655 add_cmdline_bool_option(¶meters
, "no-connect");
658 open_new_window(ses
->tab
->term
, program
.path
, env
, parameters
.source
);
659 done_string(¶meters
);
662 /* Open a link in a new xterm. */
664 send_open_in_new_window(struct terminal
*term
, const struct open_in_new
*open
,
667 struct document_view
*doc_view
;
671 assert(term
&& open
&& ses
);
672 if_assert_failed
return;
673 doc_view
= current_frame(ses
);
674 assert(doc_view
&& doc_view
->vs
&& doc_view
->document
);
675 if_assert_failed
return;
677 link
= get_current_link(doc_view
);
680 uri
= get_link_uri(ses
, doc_view
, link
);
683 open_uri_in_new_window(ses
, uri
, NULL
, open
->env
,
684 CACHE_MODE_NORMAL
, TASK_NONE
);
689 send_open_new_window(struct terminal
*term
, const struct open_in_new
*open
,
692 open_uri_in_new_window(ses
, NULL
, NULL
, open
->env
,
693 CACHE_MODE_NORMAL
, TASK_NONE
);
698 open_in_new_window(struct terminal
*term
, void *func_
, void *ses_
)
700 menu_func_T func
= func_
;
701 struct session
*ses
= ses_
;
702 struct menu_item
*mi
;
705 assert(term
&& ses
&& func
);
706 if_assert_failed
return;
708 switch (can_open_in_new(term
)) {
717 mi
= new_menu(FREE_LIST
);
721 foreach_open_in_new (posibilities
, term
->environment
) {
722 const struct open_in_new
*oi
= &open_in_new
[posibilities
];
725 func(term
, (void *) oi
, ses
);
728 add_to_menu(&mi
, oi
->text
, NULL
, ACT_MAIN_NONE
, func
, (void *) oi
, 0);
731 do_menu(term
, mi
, ses
, 1);
736 add_new_win_to_menu(struct menu_item
**mi
, unsigned char *text
,
737 struct terminal
*term
)
739 int c
= can_open_in_new(term
);
743 /* The URI is saved as session info in the master and not sent to the
744 * instance in the new window so with -no-connect or -no-home enabled
745 * it is not possible to open links URIs. For -anonymous one window
746 * should be enough. */
747 if (get_cmd_opt_bool("no-connect")
748 || get_cmd_opt_bool("no-home")
749 || get_cmd_opt_bool("anonymous"))
752 add_to_menu(mi
, text
, NULL
, ACT_MAIN_OPEN_LINK_IN_NEW_WINDOW
,
754 send_open_in_new_window
, c
- 1 ? SUBMENU
: 0);
759 do_pass_uri_to_command(struct terminal
*term
, void *command_
, void *xxx
)
761 unsigned char *command
= command_
;
763 exec_on_terminal(term
, command
, "", TERM_EXEC_BG
);
768 * - Support for passing MIME type
769 * - Merge this function with rewrite_uri(), subst_cmd(), subst_file()
770 * and subst_url(). */
771 static unsigned char *
772 format_command(unsigned char *format
, struct uri
*uri
)
774 struct string string
;
776 if (!init_string(&string
)) return NULL
;
781 while (format
[pos
] && format
[pos
] != '%') pos
++;
783 add_bytes_to_string(&string
, format
, pos
);
786 if (*format
!= '%') continue;
792 unsigned char *str
= struri(uri
);
793 int length
= get_real_uri_length(uri
);
795 add_shell_quoted_to_string(&string
,
800 add_char_to_string(&string
, '%');
803 add_bytes_to_string(&string
, format
- 1, 2);
806 if (*format
) format
++;
809 return string
.source
;
812 enum frame_event_status
813 pass_uri_to_command(struct session
*ses
, struct document_view
*doc_view
,
816 LIST_OF(struct option
) *tree
= get_opt_tree("document.uri_passing",
818 enum pass_uri_type type
= which_type
;
819 struct menu_item
*items
;
820 struct option
*option
;
826 uri
= get_uri_reference(doc_view
->document
->uri
);
831 struct link
*link
= get_current_link(doc_view
);
833 if (!link
) return FRAME_EVENT_OK
;
835 uri
= get_link_uri(ses
, doc_view
, link
);
836 if (!uri
) return FRAME_EVENT_OK
;
841 uri
= get_uri_reference(ses
->doc_view
->document
->uri
);
844 items
= new_menu(FREE_LIST
| FREE_TEXT
| FREE_DATA
| NO_INTL
);
847 return FRAME_EVENT_OK
;
850 foreach (option
, *tree
) {
851 unsigned char *text
, *data
;
853 if (!strcmp(option
->name
, "_template_"))
856 text
= stracpy(option
->name
);
859 data
= format_command(option
->value
.string
, uri
);
865 add_to_menu(&items
, text
, NULL
, ACT_MAIN_NONE
,
866 do_pass_uri_to_command
, data
, 0);
873 do_menu(ses
->tab
->term
, items
, ses
, 1);
876 do_pass_uri_to_command(ses
->tab
->term
, items
->data
, ses
);
878 mem_free(items
->data
);
879 mem_free(items
->text
);
883 return FRAME_EVENT_OK
;
886 /* The caller provides the text of the menu item, so that it can
887 * choose an available accelerator key. */
889 add_uri_command_to_menu(struct menu_item
**mi
, enum pass_uri_type type
,
892 LIST_OF(struct option
) *tree
= get_opt_tree("document.uri_passing",
894 struct option
*option
;
896 enum menu_item_flags flags
= NO_FLAG
;
897 action_id_T action_id
;
901 action_id
= ACT_MAIN_FRAME_EXTERNAL_COMMAND
;
905 action_id
= ACT_MAIN_LINK_EXTERNAL_COMMAND
;
910 action_id
= ACT_MAIN_TAB_EXTERNAL_COMMAND
;
913 foreach (option
, *tree
) {
914 if (!strcmp(option
->name
, "_template_"))
924 if (commands
== 0) return;
926 add_to_menu(mi
, text
, NULL
, action_id
, NULL
, NULL
, flags
);
930 /* The file completion menu always has two non selectable menu item at the
931 * start. First is the 'Directory:' or 'Files:' text and then a separator. */
932 #define FILE_COMPLETION_MENU_OFFSET 2
934 static struct menu_item empty_directory_menu
[] = {
935 INIT_MENU_ITEM(N_("Empty directory"), NULL
, ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
),
939 /* Builds the file completion menu. If there is only one item it is selected
940 * else the menu is launched. */
942 complete_file_menu(struct terminal
*term
, int no_elevator
, void *data
,
943 menu_func_T file_func
, menu_func_T dir_func
,
944 unsigned char *dirname
, unsigned char *filename
)
946 struct menu_item
*menu
= new_menu(FREE_LIST
| NO_INTL
);
947 struct directory_entry
*entries
, *entry
;
948 int filenamelen
= strlen(filename
);
949 int direntries
= 0, fileentries
= 0;
953 entries
= get_directory_entries(dirname
, 1);
959 for (entry
= entries
; entry
->name
; entry
++) {
961 int is_dir
= (*entry
->attrib
== 'd');
962 int is_file
= (*entry
->attrib
== '-');
964 mem_free(entry
->attrib
);
965 if ((!is_dir
&& !is_file
) || !file_can_read(entry
->name
)) {
966 mem_free(entry
->name
);
970 text
= get_filename_position(entry
->name
);
971 if (strncmp(filename
, text
, filenamelen
)
972 || (no_elevator
&& !strcmp("..", text
))) {
973 mem_free(entry
->name
);
979 add_to_menu(&menu
, _("Directories:", term
), NULL
,
980 ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
);
981 add_menu_separator(&menu
);
984 add_to_menu(&menu
, text
, NULL
, ACT_MAIN_NONE
,
985 dir_func
, entry
->name
, FREE_DATA
| SUBMENU
);
991 if (direntries
) add_menu_separator(&menu
);
992 add_to_menu(&menu
, _("Files:", term
), NULL
,
993 ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
);
994 add_menu_separator(&menu
);
997 add_to_menu(&menu
, text
, NULL
, ACT_MAIN_NONE
,
998 file_func
, entry
->name
, FREE_DATA
);
1006 if (direntries
== 0 && fileentries
== 0) {
1011 /* Only one entry */
1012 if (direntries
+ fileentries
== 1) {
1013 unsigned char *text
= menu
[FILE_COMPLETION_MENU_OFFSET
].data
;
1018 /* Complete what is already there */
1019 file_func(term
, text
, data
);
1023 /* For single directory entries open the lonely subdir if it is
1024 * not the parent elevator. */
1025 if (strcmp(&text
[strlen(dirname
)], "..")) {
1026 dir_func(term
, text
, data
);
1028 do_menu(term
, empty_directory_menu
, NULL
, 0); \
1034 /* Start with the first directory or file entry selected */
1035 do_menu(term
, menu
, data
, 0);
1039 /* Prepares the launching of the file completion menu by expanding the @path
1040 * and splitting it in directory and file name part. */
1042 auto_complete_file(struct terminal
*term
, int no_elevator
, unsigned char *path
,
1043 menu_func_T file_func
, menu_func_T dir_func
, void *data
)
1046 unsigned char *dirname
;
1047 unsigned char *filename
;
1049 assert(term
&& data
&& file_func
&& dir_func
&& data
);
1051 if (get_cmd_opt_bool("anonymous"))
1054 if (!*path
) path
= "./";
1056 /* Use the URI translation to handle ./ and ../ and ~/ expansion */
1057 uri
= get_translated_uri(path
, term
->cwd
);
1060 if (uri
->protocol
!= PROTOCOL_FILE
) {
1063 path
= get_uri_string(uri
, URI_PATH
);
1069 filename
= get_filename_position(path
);
1071 if (*filename
&& file_is_dir(path
)) {
1072 filename
= path
+ strlen(path
);
1074 } else if (*filename
&& file_exists(path
)) {
1075 /* Complete any tilde expansion */
1076 file_func(term
, path
, data
);
1080 /* Split the path into @dirname and @filename */
1083 filename
= stracpy(path
);
1086 /* Make sure the dirname has an ending slash */
1087 if (!dir_sep(path
[-1])) {
1088 unsigned char separator
= *dirname
;
1089 int dirnamelen
= path
- dirname
;
1091 insert_in_string(&dirname
, dirnamelen
, &separator
, 1);
1094 complete_file_menu(term
, no_elevator
, data
,
1095 file_func
, dir_func
, dirname
, filename
);