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
, connection_state(S_BAD_URL
),
82 if (ses
->download_uri
) done_uri(ses
->download_uri
);
83 ses
->download_uri
= uri
;
85 doc_view
= current_frame(ses
);
86 assert(doc_view
&& doc_view
->document
&& doc_view
->document
->uri
);
87 if_assert_failed
return;
89 set_session_referrer(ses
, doc_view
->document
->uri
);
90 query_file(ses
, ses
->download_uri
, ses
, start_download
, NULL
, 1);
94 save_url_as(struct session
*ses
)
96 input_dialog(ses
->tab
->term
, NULL
,
97 N_("Save URL"), N_("Enter URL"),
98 ses
, &goto_url_history
,
99 MAX_STR_LEN
, "", 0, 0, NULL
,
100 (void (*)(void *, unsigned char *)) save_url
,
105 really_exit_prog(void *ses_
)
107 struct session
*ses
= ses_
;
109 register_bottom_half(destroy_terminal
, ses
->tab
->term
);
113 dont_exit_prog(void *ses_
)
115 struct session
*ses
= ses_
;
121 query_exit(struct session
*ses
)
123 /* [gettext_accelerator_context(query_exit)] */
125 msg_box(ses
->tab
->term
, NULL
, 0,
126 N_("Exit ELinks"), ALIGN_CENTER
,
127 (ses
->tab
->term
->next
== ses
->tab
->term
->prev
&& are_there_downloads())
128 ? N_("Do you really want to exit ELinks "
129 "(and terminate all downloads)?")
130 : N_("Do you really want to exit ELinks?"),
132 MSG_BOX_BUTTON(N_("~Yes"), really_exit_prog
, B_ENTER
),
133 MSG_BOX_BUTTON(N_("~No"), dont_exit_prog
, B_ESC
));
137 exit_prog(struct session
*ses
, int query
)
141 /* An exit query is in progress. */
145 /* Force a query if the last terminal is exiting with downloads still in
147 if (query
|| (list_is_singleton(terminals
) && are_there_downloads())) {
152 really_exit_prog(ses
);
157 go_historywards(struct terminal
*term
, void *target_
, void *ses_
)
159 struct location
*target
= target_
;
160 struct session
*ses
= ses_
;
162 go_history(ses
, target
);
165 static struct menu_item no_hist_menu
[] = {
166 INIT_MENU_ITEM(N_("No history"), NULL
, ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
),
170 /* unhist == 0 => history
171 * unhist == 1 => unhistory */
173 history_menu_common(struct terminal
*term
, struct session
*ses
, int unhist
)
175 struct menu_item
*mi
= NULL
;
177 if (have_location(ses
)) {
178 struct location
*loc
;
180 for (loc
= unhist
? cur_loc(ses
)->next
: cur_loc(ses
)->prev
;
181 loc
!= (struct location
*) &ses
->history
.history
;
182 loc
= unhist
? loc
->next
: loc
->prev
) {
186 mi
= new_menu(FREE_LIST
| FREE_TEXT
| NO_INTL
);
190 url
= get_uri_string(loc
->vs
.uri
, URI_PUBLIC
);
192 add_to_menu(&mi
, url
, NULL
, ACT_MAIN_NONE
,
200 do_menu(term
, no_hist_menu
, ses
, 0);
202 do_menu(term
, mi
, ses
, 0);
206 history_menu(struct terminal
*term
, void *xxx
, void *ses_
)
208 struct session
*ses
= ses_
;
210 history_menu_common(term
, ses
, 0);
214 unhistory_menu(struct terminal
*term
, void *xxx
, void *ses_
)
216 struct session
*ses
= ses_
;
218 history_menu_common(term
, ses
, 1);
222 tab_menu(struct session
*ses
, int x
, int y
, int place_above_cursor
)
224 /* [gettext_accelerator_context(tab_menu)] */
225 struct menu_item
*menu
;
227 #ifdef CONFIG_BOOKMARKS
228 int anonymous
= get_cmd_opt_bool("anonymous");
231 assert(ses
&& ses
->tab
);
232 if_assert_failed
return;
234 tabs_count
= number_of_tabs(ses
->tab
->term
);
235 menu
= new_menu(FREE_LIST
);
238 add_menu_action(&menu
, N_("Go ~back"), ACT_MAIN_HISTORY_MOVE_BACK
);
239 add_menu_action(&menu
, N_("Go for~ward"), ACT_MAIN_HISTORY_MOVE_FORWARD
);
241 if (have_location(ses
)) {
242 add_menu_separator(&menu
);
244 #ifdef CONFIG_BOOKMARKS
246 add_menu_action(&menu
, N_("Bookm~ark document"), ACT_MAIN_ADD_BOOKMARK
);
250 add_menu_action(&menu
, N_("Toggle ~HTML/plain"), ACT_MAIN_TOGGLE_HTML_PLAIN
);
251 add_menu_action(&menu
, N_("~Reload"), ACT_MAIN_RELOAD
);
253 if (ses
->doc_view
&& document_has_frames(ses
->doc_view
->document
)) {
254 add_menu_action(&menu
, N_("Frame at ~full-screen"), ACT_MAIN_FRAME_MAXIMIZE
);
255 add_uri_command_to_menu(&menu
, PASS_URI_FRAME
,
256 N_("~Pass frame URI to external command"));
260 /* Keep tab related operations below this separator */
261 add_menu_separator(&menu
);
263 if (tabs_count
> 1) {
264 add_menu_action(&menu
, N_("Nex~t tab"), ACT_MAIN_TAB_NEXT
);
265 add_menu_action(&menu
, N_("Pre~v tab"), ACT_MAIN_TAB_PREV
);
268 add_menu_action(&menu
, N_("~Close tab"), ACT_MAIN_TAB_CLOSE
);
270 if (tabs_count
> 1) {
271 add_menu_action(&menu
, N_("C~lose all tabs but the current"),
272 ACT_MAIN_TAB_CLOSE_ALL_BUT_CURRENT
);
273 #ifdef CONFIG_BOOKMARKS
275 add_menu_action(&menu
, N_("B~ookmark all tabs"),
276 ACT_MAIN_ADD_BOOKMARK_TABS
);
281 if (have_location(ses
)) {
282 add_uri_command_to_menu(&menu
, PASS_URI_TAB
,
283 N_("Pass tab URI to e~xternal command"));
286 /* Adjust the menu position taking the menu frame into account */
287 if (place_above_cursor
) {
290 while (menu
[i
].text
) i
++;
292 y
= int_max(y
- i
- 1, 0);
295 set_window_ptr(ses
->tab
, x
, y
);
297 do_menu(ses
->tab
->term
, menu
, ses
, 1);
301 do_submenu(struct terminal
*term
, void *menu_
, void *ses_
)
303 struct menu_item
*menu
= menu_
;
305 do_menu(term
, menu
, ses_
, 1);
309 static struct menu_item file_menu11
[] = {
310 /* [gettext_accelerator_context(.file_menu)] */
311 INIT_MENU_ACTION(N_("Open new ~tab"), ACT_MAIN_OPEN_NEW_TAB
),
312 INIT_MENU_ACTION(N_("Open new tab in backgroun~d"), ACT_MAIN_OPEN_NEW_TAB_IN_BACKGROUND
),
313 INIT_MENU_ACTION(N_("~Go to URL"), ACT_MAIN_GOTO_URL
),
314 INIT_MENU_ACTION(N_("Go ~back"), ACT_MAIN_HISTORY_MOVE_BACK
),
315 INIT_MENU_ACTION(N_("Go ~forward"), ACT_MAIN_HISTORY_MOVE_FORWARD
),
316 INIT_MENU_ITEM(N_("~History"), NULL
, ACT_MAIN_NONE
, history_menu
, NULL
, SUBMENU
),
317 INIT_MENU_ITEM(N_("~Unhistory"), NULL
, ACT_MAIN_NONE
, unhistory_menu
, NULL
, SUBMENU
),
320 static struct menu_item file_menu21
[] = {
321 /* [gettext_accelerator_context(.file_menu)] */
323 INIT_MENU_ACTION(N_("~Save as"), ACT_MAIN_SAVE_AS
),
324 INIT_MENU_ACTION(N_("Save UR~L as"), ACT_MAIN_SAVE_URL_AS
),
325 INIT_MENU_ACTION(N_("Sa~ve formatted document"), ACT_MAIN_SAVE_FORMATTED
),
326 #ifdef CONFIG_BOOKMARKS
327 INIT_MENU_ACTION(N_("Bookm~ark document"), ACT_MAIN_ADD_BOOKMARK
),
331 static struct menu_item file_menu22
[] = {
332 /* [gettext_accelerator_context(.file_menu)] */
334 INIT_MENU_ACTION(N_("~Kill background connections"), ACT_MAIN_KILL_BACKGROUNDED_CONNECTIONS
),
335 INIT_MENU_ACTION(N_("Flush all ~caches"), ACT_MAIN_CACHE_MINIMIZE
),
336 INIT_MENU_ACTION(N_("Resource ~info"), ACT_MAIN_RESOURCE_INFO
),
340 static struct menu_item file_menu3
[] = {
341 /* [gettext_accelerator_context(.file_menu)] */
343 INIT_MENU_ACTION(N_("E~xit"), ACT_MAIN_QUIT
),
348 do_file_menu(struct terminal
*term
, void *xxx
, void *ses_
)
350 /* [gettext_accelerator_context(.file_menu)] */
351 struct menu_item
*file_menu
, *e
, *f
;
352 int anonymous
= get_cmd_opt_bool("anonymous");
355 file_menu
= mem_alloc(sizeof(file_menu11
) + sizeof(file_menu21
)
356 + sizeof(file_menu22
) + sizeof(file_menu3
)
357 + 3 * sizeof(struct menu_item
));
358 if (!file_menu
) return;
363 && !get_cmd_opt_bool("no-connect")
364 && !get_cmd_opt_bool("no-home"))
365 o
= can_open_in_new(term
);
370 SET_MENU_ITEM(e
, N_("Open ~new window"), NULL
, ACT_MAIN_OPEN_NEW_WINDOW
,
371 open_in_new_window
, send_open_new_window
,
372 (o
- 1) ? SUBMENU
: 0, HKS_SHOW
, 0);
376 memcpy(e
, file_menu11
, sizeof(file_menu11
));
377 e
+= sizeof_array(file_menu11
);
380 memcpy(e
, file_menu21
, sizeof(file_menu21
));
381 e
+= sizeof_array(file_menu21
);
384 memcpy(e
, file_menu22
, sizeof(file_menu22
));
385 e
+= sizeof_array(file_menu22
);
388 if (!anonymous
&& can_open_os_shell(term
->environment
)) {
389 SET_MENU_ITEM(e
, N_("~OS shell"), NULL
, ACT_MAIN_OPEN_OS_SHELL
,
390 NULL
, NULL
, 0, HKS_SHOW
, 0);
395 if (can_resize_window(term
->environment
)) {
396 SET_MENU_ITEM(e
, N_("Resize t~erminal"), NULL
, ACT_MAIN_TERMINAL_RESIZE
,
397 NULL
, NULL
, 0, HKS_SHOW
, 0);
402 memcpy(e
, file_menu3
+ x
, sizeof(file_menu3
) - x
* sizeof(struct menu_item
));
403 e
+= sizeof_array(file_menu3
);
405 for (f
= file_menu
; f
< e
; f
++)
406 f
->flags
|= FREE_LIST
;
408 do_menu(term
, file_menu
, ses_
, 1);
411 static struct menu_item view_menu
[] = {
412 /* [gettext_accelerator_context(.view_menu)] */
413 INIT_MENU_ACTION(N_("~Search"), ACT_MAIN_SEARCH
),
414 INIT_MENU_ACTION(N_("Search ~backward"), ACT_MAIN_SEARCH_BACK
),
415 INIT_MENU_ACTION(N_("Find ~next"), ACT_MAIN_FIND_NEXT
),
416 INIT_MENU_ACTION(N_("Find ~previous"), ACT_MAIN_FIND_NEXT_BACK
),
417 INIT_MENU_ACTION(N_("T~ypeahead search"), ACT_MAIN_SEARCH_TYPEAHEAD
),
419 INIT_MENU_ACTION(N_("Toggle ~HTML/plain"), ACT_MAIN_TOGGLE_HTML_PLAIN
),
420 INIT_MENU_ACTION(N_("Toggle i~mages"), ACT_MAIN_TOGGLE_DISPLAY_IMAGES
),
421 INIT_MENU_ACTION(N_("Toggle ~link numbering"), ACT_MAIN_TOGGLE_NUMBERED_LINKS
),
422 INIT_MENU_ACTION(N_("Toggle ~document colors"), ACT_MAIN_TOGGLE_DOCUMENT_COLORS
),
423 INIT_MENU_ACTION(N_("~Wrap text on/off"), ACT_MAIN_TOGGLE_WRAP_TEXT
),
425 INIT_MENU_ACTION(N_("Document ~info"), ACT_MAIN_DOCUMENT_INFO
),
426 INIT_MENU_ACTION(N_("H~eader info"), ACT_MAIN_HEADER_INFO
),
427 INIT_MENU_ACTION(N_("Rel~oad document"), ACT_MAIN_RELOAD
),
428 INIT_MENU_ACTION(N_("~Rerender document"), ACT_MAIN_RERENDER
),
429 INIT_MENU_ACTION(N_("Frame at ~full-screen"), ACT_MAIN_FRAME_MAXIMIZE
),
431 INIT_MENU_ACTION(N_("Nex~t tab"), ACT_MAIN_TAB_NEXT
),
432 INIT_MENU_ACTION(N_("Pre~v tab"), ACT_MAIN_TAB_PREV
),
433 INIT_MENU_ACTION(N_("~Close tab"), ACT_MAIN_TAB_CLOSE
),
438 static struct menu_item help_menu
[] = {
439 /* [gettext_accelerator_context(.help_menu)] */
440 INIT_MENU_ITEM(N_("~ELinks homepage"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_WEBSITE_URL
, 0),
441 INIT_MENU_ITEM(N_("~Documentation"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_DOC_URL
, 0),
442 INIT_MENU_ITEM(N_("~Keys"), NULL
, ACT_MAIN_NONE
, menu_keys
, NULL
, 0),
444 INIT_MENU_ITEM(N_("LED ~indicators"), NULL
, ACT_MAIN_NONE
, menu_leds_info
, NULL
, 0),
447 INIT_MENU_ITEM(N_("~Bugs information"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_BUGS_URL
, 0),
449 INIT_MENU_ITEM(N_("ELinks ~GITWeb"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_GITWEB_URL
, 0),
452 INIT_MENU_ITEM(N_("~Copying"), NULL
, ACT_MAIN_NONE
, menu_copying
, NULL
, 0),
453 INIT_MENU_ITEM(N_("Autho~rs"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_AUTHORS_URL
, 0),
454 INIT_MENU_ITEM(N_("~About"), NULL
, ACT_MAIN_NONE
, menu_about
, NULL
, 0),
459 static struct menu_item ext_menu
[] = {
460 /* [gettext_accelerator_context(.ext_menu)] */
461 INIT_MENU_ITEM(N_("~Add"), NULL
, ACT_MAIN_NONE
, menu_add_ext
, NULL
, 0),
462 INIT_MENU_ITEM(N_("~Modify"), NULL
, ACT_MAIN_NONE
, menu_list_ext
, menu_add_ext
, SUBMENU
),
463 INIT_MENU_ITEM(N_("~Delete"), NULL
, ACT_MAIN_NONE
, menu_list_ext
, menu_del_ext
, SUBMENU
),
467 static struct menu_item setup_menu
[] = {
468 /* [gettext_accelerator_context(.setup_menu)] */
470 INIT_MENU_ITEM(N_("~Language"), NULL
, ACT_MAIN_NONE
, menu_language_list
, NULL
, SUBMENU
),
472 INIT_MENU_ITEM(N_("C~haracter set"), NULL
, ACT_MAIN_NONE
, charset_list
, NULL
, SUBMENU
),
473 INIT_MENU_ACTION(N_("~Terminal options"), ACT_MAIN_SHOW_TERM_OPTIONS
),
474 INIT_MENU_ITEM(N_("File ~extensions"), NULL
, ACT_MAIN_NONE
, do_submenu
, ext_menu
, SUBMENU
),
476 INIT_MENU_ACTION(N_("~Options manager"), ACT_MAIN_OPTIONS_MANAGER
),
477 INIT_MENU_ACTION(N_("~Keybinding manager"), ACT_MAIN_KEYBINDING_MANAGER
),
478 INIT_MENU_ACTION(N_("~Save options"), ACT_MAIN_SAVE_OPTIONS
),
482 static struct menu_item setup_menu_anon
[] = {
483 /* [gettext_accelerator_context(.setup_menu)] */
484 INIT_MENU_ITEM(N_("~Language"), NULL
, ACT_MAIN_NONE
, menu_language_list
, NULL
, SUBMENU
),
485 INIT_MENU_ITEM(N_("C~haracter set"), NULL
, ACT_MAIN_NONE
, charset_list
, NULL
, SUBMENU
),
486 INIT_MENU_ACTION(N_("~Terminal options"), ACT_MAIN_SHOW_TERM_OPTIONS
),
490 static struct menu_item tools_menu
[] = {
491 /* [gettext_accelerator_context(.tools_menu)] */
492 #ifdef CONFIG_GLOBHIST
493 INIT_MENU_ACTION(N_("Global ~history"), ACT_MAIN_HISTORY_MANAGER
),
495 #ifdef CONFIG_BOOKMARKS
496 INIT_MENU_ACTION(N_("~Bookmarks"), ACT_MAIN_BOOKMARK_MANAGER
),
498 INIT_MENU_ACTION(N_("~Cache"), ACT_MAIN_CACHE_MANAGER
),
499 INIT_MENU_ACTION(N_("~Downloads"), ACT_MAIN_DOWNLOAD_MANAGER
),
500 #ifdef CONFIG_COOKIES
501 INIT_MENU_ACTION(N_("Coo~kies"), ACT_MAIN_COOKIE_MANAGER
),
503 #ifdef CONFIG_FORMHIST
504 INIT_MENU_ACTION(N_("~Form history"), ACT_MAIN_FORMHIST_MANAGER
),
506 INIT_MENU_ACTION(N_("~Authentication"), ACT_MAIN_AUTH_MANAGER
),
511 do_setup_menu(struct terminal
*term
, void *xxx
, void *ses_
)
513 struct session
*ses
= ses_
;
515 if (!get_cmd_opt_bool("anonymous"))
516 do_menu(term
, setup_menu
, ses
, 1);
518 do_menu(term
, setup_menu_anon
, ses
, 1);
521 static struct menu_item main_menu
[] = {
522 /* [gettext_accelerator_context(.main_menu)] */
523 INIT_MENU_ITEM(N_("~File"), NULL
, ACT_MAIN_NONE
, do_file_menu
, NULL
, FREE_LIST
| SUBMENU
),
524 INIT_MENU_ITEM(N_("~View"), NULL
, ACT_MAIN_NONE
, do_submenu
, view_menu
, FREE_LIST
| SUBMENU
),
525 INIT_MENU_ITEM(N_("~Link"), NULL
, ACT_MAIN_NONE
, link_menu
, NULL
, FREE_LIST
| SUBMENU
),
526 INIT_MENU_ITEM(N_("~Tools"), NULL
, ACT_MAIN_NONE
, do_submenu
, tools_menu
, FREE_LIST
| SUBMENU
),
527 INIT_MENU_ITEM(N_("~Setup"), NULL
, ACT_MAIN_NONE
, do_setup_menu
, NULL
, FREE_LIST
| SUBMENU
),
528 INIT_MENU_ITEM(N_("~Help"), NULL
, ACT_MAIN_NONE
, do_submenu
, help_menu
, FREE_LIST
| SUBMENU
),
533 activate_bfu_technology(struct session
*ses
, int item
)
535 do_mainmenu(ses
->tab
->term
, main_menu
, ses
, item
);
540 dialog_goto_url(struct session
*ses
, unsigned char *url
)
542 input_dialog(ses
->tab
->term
, NULL
,
543 N_("Go to URL"), N_("Enter URL"),
544 ses
, &goto_url_history
,
545 MAX_STR_LEN
, url
, 0, 0, NULL
,
546 (void (*)(void *, unsigned char *)) goto_url_with_hook
,
551 static INIT_INPUT_HISTORY(file_history
);
554 query_file(struct session
*ses
, struct uri
*uri
, void *data
,
555 void (*std
)(void *, unsigned char *),
556 void (*cancel
)(void *), int interactive
)
561 if_assert_failed
return;
563 /* FIXME: This ``sanity'' checking is mostly for the download code
564 * using this function. They pass ses->download_uri and we have to make
565 * sure that the connection code can download the URI. The reason we do
566 * it before is that then users won't waste time typing a filename and
567 * then discover that the URI can not be downloaded. However it might
568 * be better to introduce a set_session_download_uri() which will do
569 * the checking? --jonas */
571 if (uri
->protocol
== PROTOCOL_UNKNOWN
) {
572 print_error_dialog(ses
, connection_state(S_UNKNOWN_PROTOCOL
),
577 if (get_protocol_external_handler(ses
->tab
->term
, uri
)) {
578 print_error_dialog(ses
, connection_state(S_EXTERNAL_PROTOCOL
),
583 if (!init_string(&def
)) return;
585 add_to_string(&def
, get_opt_str("document.download.directory"));
586 if (def
.length
&& !dir_sep(def
.source
[def
.length
- 1]))
587 add_char_to_string(&def
, '/');
589 add_mime_filename_to_string(&def
, uri
);
591 /* Remove the %-ugliness for display */
593 if (ses
->tab
->term
->utf8_cp
)
594 decode_uri_string(&def
);
596 #endif /* CONFIG_UTF8 */
597 decode_uri_string_for_display(&def
);
600 input_dialog(ses
->tab
->term
, NULL
,
601 N_("Download"), N_("Save to file"),
603 MAX_STR_LEN
, def
.source
, 0, 0, check_nonempty
,
604 (void (*)(void *, unsigned char *)) std
,
605 (void (*)(void *)) cancel
);
607 std(data
, def
.source
);
614 free_history_lists(void)
616 free_list(file_history
.entries
);
617 #ifdef CONFIG_SCRIPTING
618 trigger_event_name("free-history");
624 add_cmdline_bool_option(struct string
*string
, unsigned char *name
)
626 if (!get_cmd_opt_bool(name
)) return;
627 add_to_string(string
, " -");
628 add_to_string(string
, name
);
632 open_uri_in_new_window(struct session
*ses
, struct uri
*uri
, struct uri
*referrer
,
633 enum term_env_type env
, enum cache_mode cache_mode
,
636 int ring
= get_cmd_opt_int("session-ring");
637 struct string parameters
;
641 if_assert_failed
return;
643 id
= add_session_info(ses
, uri
, referrer
, cache_mode
, task
);
646 if (!init_string(¶meters
)) return;
648 add_format_to_string(¶meters
, "-base-session %d", id
);
649 if (ring
) add_format_to_string(¶meters
, " -session-ring %d", ring
);
651 /* No URI means open new (clean) window possibly without connecting to
652 * the current master so add command line options to properly clone the
655 /* Adding -touch-files will only lead to problems */
656 add_cmdline_bool_option(¶meters
, "localhost");
657 add_cmdline_bool_option(¶meters
, "no-home");
658 add_cmdline_bool_option(¶meters
, "no-connect");
661 open_new_window(ses
->tab
->term
, program
.path
, env
, parameters
.source
);
662 done_string(¶meters
);
665 /* Open a link in a new xterm. */
667 send_open_in_new_window(struct terminal
*term
, const struct open_in_new
*open
,
670 struct document_view
*doc_view
;
674 assert(term
&& open
&& ses
);
675 if_assert_failed
return;
676 doc_view
= current_frame(ses
);
677 assert(doc_view
&& doc_view
->vs
&& doc_view
->document
);
678 if_assert_failed
return;
680 link
= get_current_link(doc_view
);
683 uri
= get_link_uri(ses
, doc_view
, link
);
686 open_uri_in_new_window(ses
, uri
, NULL
, open
->env
,
687 CACHE_MODE_NORMAL
, TASK_NONE
);
692 send_open_new_window(struct terminal
*term
, const struct open_in_new
*open
,
695 open_uri_in_new_window(ses
, NULL
, NULL
, open
->env
,
696 CACHE_MODE_NORMAL
, TASK_NONE
);
701 open_in_new_window(struct terminal
*term
, void *func_
, void *ses_
)
703 menu_func_T func
= func_
;
704 struct session
*ses
= ses_
;
705 struct menu_item
*mi
;
708 assert(term
&& ses
&& func
);
709 if_assert_failed
return;
711 switch (can_open_in_new(term
)) {
720 mi
= new_menu(FREE_LIST
);
724 foreach_open_in_new (posibilities
, term
->environment
) {
725 const struct open_in_new
*oi
= &open_in_new
[posibilities
];
728 func(term
, (void *) oi
, ses
);
731 add_to_menu(&mi
, oi
->text
, NULL
, ACT_MAIN_NONE
, func
, (void *) oi
, 0);
734 do_menu(term
, mi
, ses
, 1);
739 add_new_win_to_menu(struct menu_item
**mi
, unsigned char *text
,
740 struct terminal
*term
)
742 int c
= can_open_in_new(term
);
746 /* The URI is saved as session info in the master and not sent to the
747 * instance in the new window so with -no-connect or -no-home enabled
748 * it is not possible to open links URIs. For -anonymous one window
749 * should be enough. */
750 if (get_cmd_opt_bool("no-connect")
751 || get_cmd_opt_bool("no-home")
752 || get_cmd_opt_bool("anonymous"))
755 add_to_menu(mi
, text
, NULL
, ACT_MAIN_OPEN_LINK_IN_NEW_WINDOW
,
757 send_open_in_new_window
, c
- 1 ? SUBMENU
: 0);
762 do_pass_uri_to_command(struct terminal
*term
, void *command_
, void *xxx
)
764 unsigned char *command
= command_
;
766 exec_on_terminal(term
, command
, "", TERM_EXEC_BG
);
771 * - Support for passing MIME type
772 * - Merge this function with rewrite_uri(), subst_cmd(), subst_file()
773 * and subst_url(). */
774 static unsigned char *
775 format_command(unsigned char *format
, struct uri
*uri
)
777 struct string string
;
779 if (!init_string(&string
)) return NULL
;
784 while (format
[pos
] && format
[pos
] != '%') pos
++;
786 add_bytes_to_string(&string
, format
, pos
);
789 if (*format
!= '%') continue;
795 unsigned char *str
= struri(uri
);
796 int length
= get_real_uri_length(uri
);
798 add_shell_quoted_to_string(&string
,
803 add_char_to_string(&string
, '%');
806 add_bytes_to_string(&string
, format
- 1, 2);
809 if (*format
) format
++;
812 return string
.source
;
815 enum frame_event_status
816 pass_uri_to_command(struct session
*ses
, struct document_view
*doc_view
,
819 LIST_OF(struct option
) *tree
= get_opt_tree("document.uri_passing");
820 enum pass_uri_type type
= which_type
;
821 struct menu_item
*items
;
822 struct option
*option
;
828 uri
= get_uri_reference(doc_view
->document
->uri
);
833 struct link
*link
= get_current_link(doc_view
);
835 if (!link
) return FRAME_EVENT_OK
;
837 uri
= get_link_uri(ses
, doc_view
, link
);
838 if (!uri
) return FRAME_EVENT_OK
;
843 uri
= get_uri_reference(ses
->doc_view
->document
->uri
);
846 items
= new_menu(FREE_LIST
| FREE_TEXT
| FREE_DATA
| NO_INTL
);
849 return FRAME_EVENT_OK
;
852 foreach (option
, *tree
) {
853 unsigned char *text
, *data
;
855 if (!strcmp(option
->name
, "_template_"))
858 text
= stracpy(option
->name
);
861 data
= format_command(option
->value
.string
, uri
);
867 add_to_menu(&items
, text
, NULL
, ACT_MAIN_NONE
,
868 do_pass_uri_to_command
, data
, 0);
875 do_menu(ses
->tab
->term
, items
, ses
, 1);
878 do_pass_uri_to_command(ses
->tab
->term
, items
->data
, ses
);
880 mem_free(items
->data
);
881 mem_free(items
->text
);
885 return FRAME_EVENT_OK
;
888 /* The caller provides the text of the menu item, so that it can
889 * choose an available accelerator key. */
891 add_uri_command_to_menu(struct menu_item
**mi
, enum pass_uri_type type
,
894 LIST_OF(struct option
) *tree
= get_opt_tree("document.uri_passing");
895 struct option
*option
;
897 enum menu_item_flags flags
= NO_FLAG
;
898 action_id_T action_id
;
902 action_id
= ACT_MAIN_FRAME_EXTERNAL_COMMAND
;
906 action_id
= ACT_MAIN_LINK_EXTERNAL_COMMAND
;
911 action_id
= ACT_MAIN_TAB_EXTERNAL_COMMAND
;
914 foreach (option
, *tree
) {
915 if (!strcmp(option
->name
, "_template_"))
925 if (commands
== 0) return;
927 add_to_menu(mi
, text
, NULL
, action_id
, NULL
, NULL
, flags
);
931 /* The file completion menu always has two non selectable menu item at the
932 * start. First is the 'Directory:' or 'Files:' text and then a separator. */
933 #define FILE_COMPLETION_MENU_OFFSET 2
935 static struct menu_item empty_directory_menu
[] = {
936 INIT_MENU_ITEM(N_("Empty directory"), NULL
, ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
),
940 /* Builds the file completion menu. If there is only one item it is selected
941 * else the menu is launched. */
943 complete_file_menu(struct terminal
*term
, int no_elevator
, void *data
,
944 menu_func_T file_func
, menu_func_T dir_func
,
945 unsigned char *dirname
, unsigned char *filename
)
947 struct menu_item
*menu
= new_menu(FREE_LIST
| NO_INTL
);
948 struct directory_entry
*entries
, *entry
;
949 int filenamelen
= strlen(filename
);
950 int direntries
= 0, fileentries
= 0;
954 entries
= get_directory_entries(dirname
, 1);
960 for (entry
= entries
; entry
->name
; entry
++) {
962 int is_dir
= (*entry
->attrib
== 'd');
963 int is_file
= (*entry
->attrib
== '-');
965 mem_free(entry
->attrib
);
966 if ((!is_dir
&& !is_file
) || !file_can_read(entry
->name
)) {
967 mem_free(entry
->name
);
971 text
= get_filename_position(entry
->name
);
972 if (strncmp(filename
, text
, filenamelen
)
973 || (no_elevator
&& !strcmp("..", text
))) {
974 mem_free(entry
->name
);
980 add_to_menu(&menu
, _("Directories:", term
), NULL
,
981 ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
);
982 add_menu_separator(&menu
);
985 add_to_menu(&menu
, text
, NULL
, ACT_MAIN_NONE
,
986 dir_func
, entry
->name
, FREE_DATA
| SUBMENU
);
992 if (direntries
) add_menu_separator(&menu
);
993 add_to_menu(&menu
, _("Files:", term
), NULL
,
994 ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
);
995 add_menu_separator(&menu
);
998 add_to_menu(&menu
, text
, NULL
, ACT_MAIN_NONE
,
999 file_func
, entry
->name
, FREE_DATA
);
1007 if (direntries
== 0 && fileentries
== 0) {
1012 /* Only one entry */
1013 if (direntries
+ fileentries
== 1) {
1014 unsigned char *text
= menu
[FILE_COMPLETION_MENU_OFFSET
].data
;
1019 /* Complete what is already there */
1020 file_func(term
, text
, data
);
1024 /* For single directory entries open the lonely subdir if it is
1025 * not the parent elevator. */
1026 if (strcmp(&text
[strlen(dirname
)], "..")) {
1027 dir_func(term
, text
, data
);
1029 do_menu(term
, empty_directory_menu
, NULL
, 0); \
1035 /* Start with the first directory or file entry selected */
1036 do_menu(term
, menu
, data
, 0);
1040 /* Prepares the launching of the file completion menu by expanding the @path
1041 * and splitting it in directory and file name part. */
1043 auto_complete_file(struct terminal
*term
, int no_elevator
, unsigned char *path
,
1044 menu_func_T file_func
, menu_func_T dir_func
, void *data
)
1047 unsigned char *dirname
;
1048 unsigned char *filename
;
1050 assert(term
&& data
&& file_func
&& dir_func
&& data
);
1052 if (get_cmd_opt_bool("anonymous"))
1055 if (!*path
) path
= "./";
1057 /* Use the URI translation to handle ./ and ../ and ~/ expansion */
1058 uri
= get_translated_uri(path
, term
->cwd
);
1061 if (uri
->protocol
!= PROTOCOL_FILE
) {
1064 path
= get_uri_string(uri
, URI_PATH
);
1070 filename
= get_filename_position(path
);
1072 if (*filename
&& file_is_dir(path
)) {
1073 filename
= path
+ strlen(path
);
1075 } else if (*filename
&& file_exists(path
)) {
1076 /* Complete any tilde expansion */
1077 file_func(term
, path
, data
);
1081 /* Split the path into @dirname and @filename */
1084 filename
= stracpy(path
);
1087 /* Make sure the dirname has an ending slash */
1088 if (!dir_sep(path
[-1])) {
1089 unsigned char separator
= *dirname
;
1090 int dirnamelen
= path
- dirname
;
1092 insert_in_string(&dirname
, dirnamelen
, &separator
, 1);
1095 complete_file_menu(term
, no_elevator
, data
,
1096 file_func
, dir_func
, dirname
, filename
);