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(struct session
*ses
)
106 register_bottom_half(destroy_terminal
, ses
->tab
->term
);
110 dont_exit_prog(struct session
*ses
)
116 query_exit(struct session
*ses
)
119 msg_box(ses
->tab
->term
, NULL
, 0,
120 N_("Exit ELinks"), ALIGN_CENTER
,
121 (ses
->tab
->term
->next
== ses
->tab
->term
->prev
&& are_there_downloads())
122 ? N_("Do you really want to exit ELinks "
123 "(and terminate all downloads)?")
124 : N_("Do you really want to exit ELinks?"),
126 N_("~Yes"), (void (*)(void *)) really_exit_prog
, B_ENTER
,
127 N_("~No"), (void (*)(void *)) dont_exit_prog
, B_ESC
);
131 exit_prog(struct session
*ses
, int query
)
135 /* An exit query is in progress. */
139 /* Force a query if the last terminal is exiting with downloads still in
141 if (query
|| (list_is_singleton(terminals
) && are_there_downloads())) {
146 really_exit_prog(ses
);
151 go_historywards(struct terminal
*term
, void *target_
, void *ses_
)
153 struct location
*target
= target_
;
154 struct session
*ses
= ses_
;
156 go_history(ses
, target
);
159 static struct menu_item no_hist_menu
[] = {
160 INIT_MENU_ITEM(N_("No history"), NULL
, ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
),
164 /* unhist == 0 => history
165 * unhist == 1 => unhistory */
167 history_menu_common(struct terminal
*term
, struct session
*ses
, int unhist
)
169 struct menu_item
*mi
= NULL
;
171 if (have_location(ses
)) {
172 struct location
*loc
;
174 for (loc
= unhist
? cur_loc(ses
)->next
: cur_loc(ses
)->prev
;
175 loc
!= (struct location
*) &ses
->history
.history
;
176 loc
= unhist
? loc
->next
: loc
->prev
) {
180 mi
= new_menu(FREE_LIST
| FREE_TEXT
| NO_INTL
);
184 url
= get_uri_string(loc
->vs
.uri
, URI_PUBLIC
);
186 add_to_menu(&mi
, url
, NULL
, ACT_MAIN_NONE
,
194 do_menu(term
, no_hist_menu
, ses
, 0);
196 do_menu(term
, mi
, ses
, 0);
200 history_menu(struct terminal
*term
, void *xxx
, void *ses_
)
202 struct session
*ses
= ses_
;
204 history_menu_common(term
, ses
, 0);
208 unhistory_menu(struct terminal
*term
, void *xxx
, void *ses_
)
210 struct session
*ses
= ses_
;
212 history_menu_common(term
, ses
, 1);
216 tab_menu(struct session
*ses
, int x
, int y
, int place_above_cursor
)
218 struct menu_item
*menu
;
220 #ifdef CONFIG_BOOKMARKS
221 int anonymous
= get_cmd_opt_bool("anonymous");
224 assert(ses
&& ses
->tab
);
225 if_assert_failed
return;
227 tabs
= number_of_tabs(ses
->tab
->term
);
228 menu
= new_menu(FREE_LIST
);
231 add_menu_action(&menu
, N_("Go ~back"), ACT_MAIN_HISTORY_MOVE_BACK
);
232 add_menu_action(&menu
, N_("Go for~ward"), ACT_MAIN_HISTORY_MOVE_FORWARD
);
234 if (have_location(ses
)) {
235 add_menu_separator(&menu
);
237 #ifdef CONFIG_BOOKMARKS
239 add_menu_action(&menu
, N_("Bookm~ark document"), ACT_MAIN_ADD_BOOKMARK
);
243 add_menu_action(&menu
, N_("Toggle ~html/plain"), ACT_MAIN_TOGGLE_HTML_PLAIN
);
244 add_menu_action(&menu
, N_("~Reload"), ACT_MAIN_RELOAD
);
246 if (ses
->doc_view
&& document_has_frames(ses
->doc_view
->document
)) {
247 add_menu_action(&menu
, N_("Frame at ~full-screen"), ACT_MAIN_FRAME_MAXIMIZE
);
248 add_uri_command_to_menu(&menu
, PASS_URI_FRAME
);
252 /* Keep tab related operations below this separator */
253 add_menu_separator(&menu
);
256 add_menu_action(&menu
, N_("Nex~t tab"), ACT_MAIN_TAB_NEXT
);
257 add_menu_action(&menu
, N_("Pre~v tab"), ACT_MAIN_TAB_PREV
);
260 add_menu_action(&menu
, N_("~Close tab"), ACT_MAIN_TAB_CLOSE
);
263 add_menu_action(&menu
, N_("C~lose all tabs but the current"),
264 ACT_MAIN_TAB_CLOSE_ALL_BUT_CURRENT
);
265 #ifdef CONFIG_BOOKMARKS
267 add_menu_action(&menu
, N_("B~ookmark all tabs"),
268 ACT_MAIN_ADD_BOOKMARK_TABS
);
273 if (have_location(ses
))
274 add_uri_command_to_menu(&menu
, PASS_URI_TAB
);
276 /* Adjust the menu position taking the menu frame into account */
277 if (place_above_cursor
) {
280 while (menu
[i
].text
) i
++;
282 y
= int_max(y
- i
- 1, 0);
285 set_window_ptr(ses
->tab
, x
, y
);
287 do_menu(ses
->tab
->term
, menu
, ses
, 1);
291 do_submenu(struct terminal
*term
, void *menu_
, void *ses_
)
293 struct menu_item
*menu
= menu_
;
295 do_menu(term
, menu
, ses_
, 1);
299 static struct menu_item file_menu11
[] = {
300 INIT_MENU_ACTION(N_("Open new ~tab"), ACT_MAIN_OPEN_NEW_TAB
),
301 INIT_MENU_ACTION(N_("Open new tab in backgroun~d"), ACT_MAIN_OPEN_NEW_TAB_IN_BACKGROUND
),
302 INIT_MENU_ACTION(N_("~Go to URL"), ACT_MAIN_GOTO_URL
),
303 INIT_MENU_ACTION(N_("Go ~back"), ACT_MAIN_HISTORY_MOVE_BACK
),
304 INIT_MENU_ACTION(N_("Go ~forward"), ACT_MAIN_HISTORY_MOVE_FORWARD
),
305 INIT_MENU_ITEM(N_("~History"), NULL
, ACT_MAIN_NONE
, history_menu
, NULL
, SUBMENU
),
306 INIT_MENU_ITEM(N_("~Unhistory"), NULL
, ACT_MAIN_NONE
, unhistory_menu
, NULL
, SUBMENU
),
309 static struct menu_item file_menu21
[] = {
311 INIT_MENU_ACTION(N_("~Save as"), ACT_MAIN_SAVE_AS
),
312 INIT_MENU_ACTION(N_("Save UR~L as"), ACT_MAIN_SAVE_URL_AS
),
313 INIT_MENU_ACTION(N_("Sa~ve formatted document"), ACT_MAIN_SAVE_FORMATTED
),
314 #ifdef CONFIG_BOOKMARKS
315 INIT_MENU_ACTION(N_("Bookm~ark document"), ACT_MAIN_ADD_BOOKMARK
),
319 static struct menu_item file_menu22
[] = {
321 INIT_MENU_ACTION(N_("~Kill background connections"), ACT_MAIN_KILL_BACKGROUNDED_CONNECTIONS
),
322 INIT_MENU_ACTION(N_("Flush all ~caches"), ACT_MAIN_CACHE_MINIMIZE
),
323 INIT_MENU_ACTION(N_("Resource ~info"), ACT_MAIN_RESOURCE_INFO
),
327 static struct menu_item file_menu3
[] = {
329 INIT_MENU_ACTION(N_("E~xit"), ACT_MAIN_QUIT
),
334 do_file_menu(struct terminal
*term
, void *xxx
, void *ses_
)
336 struct menu_item
*file_menu
, *e
, *f
;
337 int anonymous
= get_cmd_opt_bool("anonymous");
340 file_menu
= mem_alloc(sizeof(file_menu11
) + sizeof(file_menu21
)
341 + sizeof(file_menu22
) + sizeof(file_menu3
)
342 + 3 * sizeof(struct menu_item
));
343 if (!file_menu
) return;
348 && !get_cmd_opt_bool("no-connect")
349 && !get_cmd_opt_bool("no-home"))
350 o
= can_open_in_new(term
);
355 SET_MENU_ITEM(e
, N_("Open ~new window"), NULL
, ACT_MAIN_OPEN_NEW_WINDOW
,
356 open_in_new_window
, send_open_new_window
,
357 (o
- 1) ? SUBMENU
: 0, 0, HKS_SHOW
);
361 memcpy(e
, file_menu11
, sizeof(file_menu11
));
362 e
+= sizeof_array(file_menu11
);
365 memcpy(e
, file_menu21
, sizeof(file_menu21
));
366 e
+= sizeof_array(file_menu21
);
369 memcpy(e
, file_menu22
, sizeof(file_menu22
));
370 e
+= sizeof_array(file_menu22
);
373 if (!anonymous
&& can_open_os_shell(term
->environment
)) {
374 SET_MENU_ITEM(e
, N_("~OS shell"), NULL
, ACT_MAIN_OPEN_OS_SHELL
,
375 NULL
, NULL
, 0, 0, HKS_SHOW
);
380 if (can_resize_window(term
->environment
)) {
381 SET_MENU_ITEM(e
, N_("Resize t~erminal"), NULL
, ACT_MAIN_TERMINAL_RESIZE
,
382 NULL
, NULL
, 0, 0, HKS_SHOW
);
387 memcpy(e
, file_menu3
+ x
, sizeof(file_menu3
) - x
* sizeof(struct menu_item
));
388 e
+= sizeof_array(file_menu3
);
390 for (f
= file_menu
; f
< e
; f
++)
391 f
->flags
|= FREE_LIST
;
393 do_menu(term
, file_menu
, ses_
, 1);
396 static struct menu_item view_menu
[] = {
397 INIT_MENU_ACTION(N_("~Search"), ACT_MAIN_SEARCH
),
398 INIT_MENU_ACTION(N_("Search ~backward"), ACT_MAIN_SEARCH_BACK
),
399 INIT_MENU_ACTION(N_("Find ~next"), ACT_MAIN_FIND_NEXT
),
400 INIT_MENU_ACTION(N_("Find ~previous"), ACT_MAIN_FIND_NEXT_BACK
),
401 INIT_MENU_ACTION(N_("T~ypeahead search"), ACT_MAIN_SEARCH_TYPEAHEAD
),
403 INIT_MENU_ACTION(N_("Toggle ~html/plain"), ACT_MAIN_TOGGLE_HTML_PLAIN
),
404 INIT_MENU_ACTION(N_("Toggle i~mages"), ACT_MAIN_TOGGLE_DISPLAY_IMAGES
),
405 INIT_MENU_ACTION(N_("Toggle ~link numbering"), ACT_MAIN_TOGGLE_NUMBERED_LINKS
),
406 INIT_MENU_ACTION(N_("Toggle ~document colors"), ACT_MAIN_TOGGLE_DOCUMENT_COLORS
),
407 INIT_MENU_ACTION(N_("~Wrap text on/off"), ACT_MAIN_TOGGLE_WRAP_TEXT
),
409 INIT_MENU_ACTION(N_("Document ~info"), ACT_MAIN_DOCUMENT_INFO
),
410 INIT_MENU_ACTION(N_("H~eader info"), ACT_MAIN_HEADER_INFO
),
411 INIT_MENU_ACTION(N_("Rel~oad document"), ACT_MAIN_RELOAD
),
412 INIT_MENU_ACTION(N_("~Rerender document"), ACT_MAIN_RERENDER
),
413 INIT_MENU_ACTION(N_("Frame at ~full-screen"), ACT_MAIN_FRAME_MAXIMIZE
),
415 INIT_MENU_ACTION(N_("Nex~t tab"), ACT_MAIN_TAB_NEXT
),
416 INIT_MENU_ACTION(N_("Pre~v tab"), ACT_MAIN_TAB_PREV
),
417 INIT_MENU_ACTION(N_("~Close tab"), ACT_MAIN_TAB_CLOSE
),
422 static struct menu_item help_menu
[] = {
423 INIT_MENU_ITEM(N_("~ELinks homepage"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_HOMEPAGE
, 0),
424 INIT_MENU_ITEM(N_("~Documentation"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_DOC_URL
, 0),
425 INIT_MENU_ITEM(N_("~Keys"), NULL
, ACT_MAIN_NONE
, menu_keys
, NULL
, 0),
427 INIT_MENU_ITEM(N_("LED ~indicators"), NULL
, ACT_MAIN_NONE
, menu_leds_info
, NULL
, 0),
430 INIT_MENU_ITEM(N_("~Bugs information"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_BUGS_URL
, 0),
432 INIT_MENU_ITEM(N_("ELinks ~GITWeb"), NULL
, ACT_MAIN_NONE
, menu_url_shortcut
, ELINKS_GITWEB_URL
, 0),
435 INIT_MENU_ITEM(N_("~Copying"), NULL
, ACT_MAIN_NONE
, menu_copying
, NULL
, 0),
436 INIT_MENU_ITEM(N_("~About"), NULL
, ACT_MAIN_NONE
, menu_about
, NULL
, 0),
441 static struct menu_item ext_menu
[] = {
442 INIT_MENU_ITEM(N_("~Add"), NULL
, ACT_MAIN_NONE
, menu_add_ext
, NULL
, 0),
443 INIT_MENU_ITEM(N_("~Modify"), NULL
, ACT_MAIN_NONE
, menu_list_ext
, menu_add_ext
, SUBMENU
),
444 INIT_MENU_ITEM(N_("~Delete"), NULL
, ACT_MAIN_NONE
, menu_list_ext
, menu_del_ext
, SUBMENU
),
448 static struct menu_item setup_menu
[] = {
450 INIT_MENU_ITEM(N_("~Language"), NULL
, ACT_MAIN_NONE
, menu_language_list
, NULL
, SUBMENU
),
452 INIT_MENU_ITEM(N_("C~haracter set"), NULL
, ACT_MAIN_NONE
, charset_list
, NULL
, SUBMENU
),
453 INIT_MENU_ACTION(N_("~Terminal options"), ACT_MAIN_SHOW_TERM_OPTIONS
),
454 INIT_MENU_ITEM(N_("File ~extensions"), NULL
, ACT_MAIN_NONE
, do_submenu
, ext_menu
, SUBMENU
),
456 INIT_MENU_ACTION(N_("~Options manager"), ACT_MAIN_OPTIONS_MANAGER
),
457 INIT_MENU_ACTION(N_("~Keybinding manager"), ACT_MAIN_KEYBINDING_MANAGER
),
458 INIT_MENU_ACTION(N_("~Save options"), ACT_MAIN_SAVE_OPTIONS
),
462 static struct menu_item setup_menu_anon
[] = {
463 INIT_MENU_ITEM(N_("~Language"), NULL
, ACT_MAIN_NONE
, menu_language_list
, NULL
, SUBMENU
),
464 INIT_MENU_ITEM(N_("C~haracter set"), NULL
, ACT_MAIN_NONE
, charset_list
, NULL
, SUBMENU
),
465 INIT_MENU_ACTION(N_("~Terminal options"), ACT_MAIN_SHOW_TERM_OPTIONS
),
469 static struct menu_item tools_menu
[] = {
470 #ifdef CONFIG_GLOBHIST
471 INIT_MENU_ACTION(N_("Global ~history"), ACT_MAIN_HISTORY_MANAGER
),
473 #ifdef CONFIG_BOOKMARKS
474 INIT_MENU_ACTION(N_("~Bookmarks"), ACT_MAIN_BOOKMARK_MANAGER
),
476 INIT_MENU_ACTION(N_("~Cache"), ACT_MAIN_CACHE_MANAGER
),
477 INIT_MENU_ACTION(N_("~Downloads"), ACT_MAIN_DOWNLOAD_MANAGER
),
478 #ifdef CONFIG_COOKIES
479 INIT_MENU_ACTION(N_("Coo~kies"), ACT_MAIN_COOKIE_MANAGER
),
481 #ifdef CONFIG_FORMHIST
482 INIT_MENU_ACTION(N_("~Form history"), ACT_MAIN_FORMHIST_MANAGER
),
484 INIT_MENU_ACTION(N_("~Authentication"), ACT_MAIN_AUTH_MANAGER
),
489 do_setup_menu(struct terminal
*term
, void *xxx
, void *ses_
)
491 struct session
*ses
= ses_
;
493 if (!get_cmd_opt_bool("anonymous"))
494 do_menu(term
, setup_menu
, ses
, 1);
496 do_menu(term
, setup_menu_anon
, ses
, 1);
499 static struct menu_item main_menu
[] = {
500 INIT_MENU_ITEM(N_("~File"), NULL
, ACT_MAIN_NONE
, do_file_menu
, NULL
, FREE_LIST
| SUBMENU
),
501 INIT_MENU_ITEM(N_("~View"), NULL
, ACT_MAIN_NONE
, do_submenu
, view_menu
, FREE_LIST
| SUBMENU
),
502 INIT_MENU_ITEM(N_("~Link"), NULL
, ACT_MAIN_NONE
, link_menu
, NULL
, FREE_LIST
| SUBMENU
),
503 INIT_MENU_ITEM(N_("~Tools"), NULL
, ACT_MAIN_NONE
, do_submenu
, tools_menu
, FREE_LIST
| SUBMENU
),
504 INIT_MENU_ITEM(N_("~Setup"), NULL
, ACT_MAIN_NONE
, do_setup_menu
, NULL
, FREE_LIST
| SUBMENU
),
505 INIT_MENU_ITEM(N_("~Help"), NULL
, ACT_MAIN_NONE
, do_submenu
, help_menu
, FREE_LIST
| SUBMENU
),
510 activate_bfu_technology(struct session
*ses
, int item
)
512 do_mainmenu(ses
->tab
->term
, main_menu
, ses
, item
);
517 dialog_goto_url(struct session
*ses
, unsigned char *url
)
519 input_dialog(ses
->tab
->term
, NULL
,
520 N_("Go to URL"), N_("Enter URL"),
521 ses
, &goto_url_history
,
522 MAX_STR_LEN
, url
, 0, 0, NULL
,
523 (void (*)(void *, unsigned char *)) goto_url_with_hook
,
528 static INIT_INPUT_HISTORY(file_history
);
531 query_file(struct session
*ses
, struct uri
*uri
, void *data
,
532 void (*std
)(void *, unsigned char *),
533 void (*cancel
)(void *), int interactive
)
538 if_assert_failed
return;
540 /* FIXME: This ``sanity'' checking is mostly for the download code
541 * using this function. They pass ses->download_uri and we have to make
542 * sure that the connection code can download the URI. The reason we do
543 * it before is that then users won't waste time typing a filename and
544 * then discover that the URI can not be downloaded. However it might
545 * be better to introduce a set_session_download_uri() which will do
546 * the checking? --jonas */
548 if (uri
->protocol
== PROTOCOL_UNKNOWN
) {
549 print_error_dialog(ses
, S_UNKNOWN_PROTOCOL
, uri
, PRI_CANCEL
);
553 if (get_protocol_external_handler(ses
->tab
->term
, uri
)) {
554 print_error_dialog(ses
, S_EXTERNAL_PROTOCOL
, uri
, PRI_CANCEL
);
558 if (!init_string(&def
)) return;
560 add_to_string(&def
, get_opt_str("document.download.directory"));
561 if (def
.length
&& !dir_sep(def
.source
[def
.length
- 1]))
562 add_char_to_string(&def
, '/');
564 add_mime_filename_to_string(&def
, uri
);
566 /* Remove the %-ugliness for display */
567 decode_uri_string_for_display(&def
);
570 input_dialog(ses
->tab
->term
, NULL
,
571 N_("Download"), N_("Save to file"),
573 MAX_STR_LEN
, def
.source
, 0, 0, check_nonempty
,
574 (void (*)(void *, unsigned char *)) std
,
575 (void (*)(void *)) cancel
);
577 std(data
, def
.source
);
584 free_history_lists(void)
586 free_list(file_history
.entries
);
587 #ifdef CONFIG_SCRIPTING
588 trigger_event_name("free-history");
594 add_cmdline_bool_option(struct string
*string
, unsigned char *name
)
596 if (!get_cmd_opt_bool(name
)) return;
597 add_to_string(string
, " -");
598 add_to_string(string
, name
);
602 open_uri_in_new_window(struct session
*ses
, struct uri
*uri
, struct uri
*referrer
,
603 enum term_env_type env
, enum cache_mode cache_mode
,
606 int ring
= get_cmd_opt_int("session-ring");
607 struct string parameters
;
611 if_assert_failed
return;
613 id
= add_session_info(ses
, uri
, referrer
, cache_mode
, task
);
616 if (!init_string(¶meters
)) return;
618 add_format_to_string(¶meters
, "-base-session %d", id
);
619 if (ring
) add_format_to_string(¶meters
, " -session-ring %d", ring
);
621 /* No URI means open new (clean) window possibly without connecting to
622 * the current master so add command line options to properly clone the
625 /* Adding -touch-files will only lead to problems */
626 add_cmdline_bool_option(¶meters
, "localhost");
627 add_cmdline_bool_option(¶meters
, "no-home");
628 add_cmdline_bool_option(¶meters
, "no-connect");
631 open_new_window(ses
->tab
->term
, program
.path
, env
, parameters
.source
);
632 done_string(¶meters
);
635 /* Open a link in a new xterm. */
637 send_open_in_new_window(struct terminal
*term
, const struct open_in_new
*open
,
640 struct document_view
*doc_view
;
644 assert(term
&& open
&& ses
);
645 if_assert_failed
return;
646 doc_view
= current_frame(ses
);
647 assert(doc_view
&& doc_view
->vs
&& doc_view
->document
);
648 if_assert_failed
return;
650 link
= get_current_link(doc_view
);
653 uri
= get_link_uri(ses
, doc_view
, link
);
656 open_uri_in_new_window(ses
, uri
, NULL
, open
->env
,
657 CACHE_MODE_NORMAL
, TASK_NONE
);
662 send_open_new_window(struct terminal
*term
, const struct open_in_new
*open
,
665 open_uri_in_new_window(ses
, NULL
, NULL
, open
->env
,
666 CACHE_MODE_NORMAL
, TASK_NONE
);
671 open_in_new_window(struct terminal
*term
, void *func_
, void *ses_
)
673 menu_func_T func
= func_
;
674 struct session
*ses
= ses_
;
675 struct menu_item
*mi
;
678 assert(term
&& ses
&& func
);
679 if_assert_failed
return;
681 switch (can_open_in_new(term
)) {
690 mi
= new_menu(FREE_LIST
);
694 foreach_open_in_new (posibilities
, term
->environment
) {
695 const struct open_in_new
*oi
= &open_in_new
[posibilities
];
698 func(term
, (void *) oi
, ses
);
701 add_to_menu(&mi
, oi
->text
, NULL
, ACT_MAIN_NONE
, func
, (void *) oi
, 0);
704 do_menu(term
, mi
, ses
, 1);
709 add_new_win_to_menu(struct menu_item
**mi
, unsigned char *text
,
710 struct terminal
*term
)
712 int c
= can_open_in_new(term
);
716 /* The URI is saved as session info in the master and not sent to the
717 * instance in the new window so with -no-connect or -no-home enabled
718 * it is not possible to open links URIs. For -anonymous one window
719 * should be enough. */
720 if (get_cmd_opt_bool("no-connect")
721 || get_cmd_opt_bool("no-home")
722 || get_cmd_opt_bool("anonymous"))
725 add_to_menu(mi
, text
, NULL
, ACT_MAIN_OPEN_LINK_IN_NEW_WINDOW
,
727 send_open_in_new_window
, c
- 1 ? SUBMENU
: 0);
732 do_pass_uri_to_command(struct terminal
*term
, void *command_
, void *xxx
)
734 unsigned char *command
= command_
;
736 exec_on_terminal(term
, command
, "", 0);
741 * - Support for passing MIME type
742 * - Merge this function with rewrite_uri(), subst_cmd(), subst_file()
743 * and subst_url(). */
744 static unsigned char *
745 format_command(unsigned char *format
, struct uri
*uri
)
747 struct string string
;
749 if (!init_string(&string
)) return NULL
;
754 while (format
[pos
] && format
[pos
] != '%') pos
++;
756 add_bytes_to_string(&string
, format
, pos
);
759 if (*format
!= '%') continue;
765 unsigned char *str
= struri(uri
);
766 int length
= get_real_uri_length(uri
);
768 add_shell_quoted_to_string(&string
,
773 add_char_to_string(&string
, '%');
776 add_bytes_to_string(&string
, format
- 1, 2);
779 if (*format
) format
++;
782 return string
.source
;
785 enum frame_event_status
786 pass_uri_to_command(struct session
*ses
, struct document_view
*doc_view
,
789 struct list_head
*tree
= get_opt_tree("document.uri_passing");
790 enum pass_uri_type type
= which_type
;
791 struct menu_item
*items
;
792 struct option
*option
;
798 uri
= get_uri_reference(doc_view
->document
->uri
);
803 struct link
*link
= get_current_link(doc_view
);
805 if (!link
) return FRAME_EVENT_OK
;
807 uri
= get_link_uri(ses
, doc_view
, link
);
808 if (!uri
) return FRAME_EVENT_OK
;
813 uri
= get_uri_reference(ses
->doc_view
->document
->uri
);
816 items
= new_menu(FREE_LIST
| FREE_TEXT
| FREE_DATA
| NO_INTL
);
819 return FRAME_EVENT_OK
;
822 foreach (option
, *tree
) {
823 unsigned char *text
, *data
;
825 if (!strcmp(option
->name
, "_template_"))
828 text
= stracpy(option
->name
);
831 data
= format_command(option
->value
.string
, uri
);
837 add_to_menu(&items
, text
, NULL
, ACT_MAIN_NONE
,
838 do_pass_uri_to_command
, data
, 0);
845 do_menu(ses
->tab
->term
, items
, ses
, 1);
848 do_pass_uri_to_command(ses
->tab
->term
, items
->data
, ses
);
850 mem_free(items
->data
);
851 mem_free(items
->text
);
855 return FRAME_EVENT_OK
;
859 add_uri_command_to_menu(struct menu_item
**mi
, enum pass_uri_type type
)
861 struct list_head
*tree
= get_opt_tree("document.uri_passing");
862 struct option
*option
;
864 enum menu_item_flags flags
= NO_FLAG
;
865 action_id_T action_id
;
870 action_id
= ACT_MAIN_FRAME_EXTERNAL_COMMAND
;
871 text
= N_("~Pass frame URI to external command");
875 action_id
= ACT_MAIN_LINK_EXTERNAL_COMMAND
;
876 text
= N_("Pass link URI to e~xternal command");
881 action_id
= ACT_MAIN_TAB_EXTERNAL_COMMAND
;
882 text
= N_("Pass tab URI to e~xternal command");
885 foreach (option
, *tree
) {
886 if (!strcmp(option
->name
, "_template_"))
896 if (commands
== 0) return;
898 add_to_menu(mi
, text
, NULL
, action_id
, NULL
, NULL
, flags
);
902 /* The file completion menu always has two non selectable menu item at the
903 * start. First is the 'Directory:' or 'Files:' text and then a separator. */
904 #define FILE_COMPLETION_MENU_OFFSET 2
906 static struct menu_item empty_directory_menu
[] = {
907 INIT_MENU_ITEM(N_("Empty directory"), NULL
, ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
),
911 /* Builds the file completion menu. If there is only one item it is selected
912 * else the menu is launched. */
914 complete_file_menu(struct terminal
*term
, int no_elevator
, void *data
,
915 menu_func_T file_func
, menu_func_T dir_func
,
916 unsigned char *dirname
, unsigned char *filename
)
918 struct menu_item
*menu
= new_menu(FREE_LIST
| NO_INTL
);
919 struct directory_entry
*entries
, *entry
;
920 int filenamelen
= strlen(filename
);
921 int direntries
= 0, fileentries
= 0;
925 entries
= get_directory_entries(dirname
, 1);
931 for (entry
= entries
; entry
->name
; entry
++) {
933 int is_dir
= (*entry
->attrib
== 'd');
934 int is_file
= (*entry
->attrib
== '-');
936 mem_free(entry
->attrib
);
937 if ((!is_dir
&& !is_file
) || !file_can_read(entry
->name
)) {
938 mem_free(entry
->name
);
942 text
= get_filename_position(entry
->name
);
943 if (strncmp(filename
, text
, filenamelen
)
944 || (no_elevator
&& !strcmp("..", text
))) {
945 mem_free(entry
->name
);
951 add_to_menu(&menu
, _("Directories:", term
), NULL
,
952 ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
);
953 add_menu_separator(&menu
);
956 add_to_menu(&menu
, text
, NULL
, ACT_MAIN_NONE
,
957 dir_func
, entry
->name
, FREE_DATA
| SUBMENU
);
963 if (direntries
) add_menu_separator(&menu
);
964 add_to_menu(&menu
, _("Files:", term
), NULL
,
965 ACT_MAIN_NONE
, NULL
, NULL
, NO_SELECT
);
966 add_menu_separator(&menu
);
969 add_to_menu(&menu
, text
, NULL
, ACT_MAIN_NONE
,
970 file_func
, entry
->name
, FREE_DATA
);
978 if (direntries
== 0 && fileentries
== 0) {
984 if (direntries
+ fileentries
== 1) {
985 unsigned char *text
= menu
[FILE_COMPLETION_MENU_OFFSET
].data
;
990 /* Complete what is already there */
991 file_func(term
, text
, data
);
995 /* For single directory entries open the lonely subdir if it is
996 * not the parent elevator. */
997 if (strcmp(&text
[strlen(dirname
)], "..")) {
998 dir_func(term
, text
, data
);
1000 do_menu(term
, empty_directory_menu
, NULL
, 0); \
1006 /* Start with the first directory or file entry selected */
1007 do_menu(term
, menu
, data
, 0);
1011 /* Prepares the launching of the file completion menu by expanding the @path
1012 * and splitting it in directory and file name part. */
1014 auto_complete_file(struct terminal
*term
, int no_elevator
, unsigned char *path
,
1015 menu_func_T file_func
, menu_func_T dir_func
, void *data
)
1018 unsigned char *dirname
;
1019 unsigned char *filename
;
1021 assert(term
&& data
&& file_func
&& dir_func
&& data
);
1023 if (get_cmd_opt_bool("anonymous"))
1026 if (!*path
) path
= "./";
1028 /* Use the URI translation to handle ./ and ../ and ~/ expansion */
1029 uri
= get_translated_uri(path
, term
->cwd
);
1032 if (uri
->protocol
!= PROTOCOL_FILE
) {
1035 path
= get_uri_string(uri
, URI_PATH
);
1041 filename
= get_filename_position(path
);
1043 if (*filename
&& file_is_dir(path
)) {
1044 filename
= path
+ strlen(path
);
1046 } else if (*filename
&& file_exists(path
)) {
1047 /* Complete any tilde expansion */
1048 file_func(term
, path
, data
);
1052 /* Split the path into @dirname and @filename */
1055 filename
= stracpy(path
);
1058 /* Make sure the dirname has an ending slash */
1059 if (!dir_sep(path
[-1])) {
1060 unsigned char separator
= *dirname
;
1061 int dirnamelen
= path
- dirname
;
1063 insert_in_string(&dirname
, dirnamelen
, &separator
, 1);
1066 complete_file_menu(term
, no_elevator
, data
,
1067 file_func
, dir_func
, dirname
, filename
);