2 * (C) Copyright 2008 Jeremy Maitin-Shepard
3 * (C) Copyright 2009-2010 John Foerch
5 * Use, modification, and distribution are subject to the terms specified in the
11 require("mime-type-override.js");
13 define_mime_type_table("content_handlers", {},
14 "A mime type table mapping mime types to content handlers. This table "+
15 "will be checked for a match when a navigation event causes Conkeror "+
16 "to encounter a mime type which is not supported by Mozilla. If no "+
17 "appropriate content handler is found in this table, the user will "+
18 "be prompted to choose from among common actions.");
21 * content_handler_context is a datatype for storing contextual information
22 * that can be used by content handlers, such as window, buffer, frame, and
23 * the download launcher object. It will also contain an abort method to
24 * abort the download. Download helper actions are passed an object of this
27 function content_handler_context (launcher, context) {
28 this.launcher = launcher;
30 this.frame = context.QueryInterface(Ci.nsIInterfaceRequestor)
31 .getInterface(Ci.nsIDOMWindowInternal);
32 this.window = get_window_from_frame(this.frame);
33 this.buffer = get_buffer_from_frame(this.frame);
35 this.window = get_recent_conkeror_window();
37 this.buffer = this.window.buffers.current;
38 this.frame = this.buffer.focused_frame; //doesn't necessarily exist for all buffer types
42 content_handler_context.prototype = {
43 constructor: content_handler_context,
49 const NS_BINDING_ABORTED = 0x804b0002;
50 this.launcher.cancel(NS_BINDING_ABORTED);
56 * The content_handler_* functions below are all things that conkeror
57 * is able to do when Mozilla has invoked download_helper because of an
58 * attempt to navigate to a document of an unsupported mime type.
60 function content_handler_save (ctx) {
61 var suggested_path = suggest_save_path_from_file_name(
62 ctx.launcher.suggestedFileName, ctx.buffer);
63 var file = yield ctx.window.minibuffer.read_file_check_overwrite(
64 $prompt = "Save to file:",
65 $initial_value = suggested_path,
67 register_download(ctx.buffer, ctx.launcher.source);
68 ctx.launcher.saveToDisk(file, false);
71 function content_handler_save_in (path, inhibit_prompt) {
72 path = make_file(path);
73 return function (ctx) {
75 var suggested_path = path.clone();
76 suggested_path.append(ctx.launcher.suggestedFileName);
78 file = suggested_path;
80 file = yield ctx.window.minibuffer.read_file_check_overwrite(
81 $prompt = "Save to file:",
82 $initial_value = suggested_path.path,
85 register_download(ctx.buffer, ctx.launcher.source);
86 ctx.launcher.saveToDisk(file, false);
90 function content_handler_open (ctx) {
91 var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
92 var mime_type = ctx.launcher.MIMEInfo.MIMEType;
93 var suggested_action = external_content_handlers.get(mime_type);
94 var command = yield ctx.window.minibuffer.read_shell_command(
95 $initial_value = suggested_action,
97 var file = get_temporary_file(ctx.launcher.suggestedFileName);
98 var info = register_download(ctx.buffer, ctx.launcher.source);
99 info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
100 info.set_shell_command(command, cwd);
101 ctx.launcher.saveToDisk(file, false);
104 function content_handler_open_default_viewer (ctx) {
105 var cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
106 var mime_type = ctx.launcher.MIMEInfo.MIMEType;
107 var command = external_content_handlers.get(mime_type);
109 command = yield ctx.window.minibuffer.read_shell_command(
110 $initial_value = command,
112 var file = get_temporary_file(ctx.launcher.suggestedFileName);
113 var info = register_download(ctx.buffer, ctx.launcher.source);
114 info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
115 info.set_shell_command(command, cwd);
116 ctx.launcher.saveToDisk(file, false);
119 function content_handler_open_url (ctx) {
120 ctx.abort(); // abort download
121 let mime_type = ctx.launcher.MIMEInfo.MIMEType;
122 let cwd = with_current_buffer(ctx.buffer, function (I) I.local.cwd);
123 let cmd = yield ctx.window.minibuffer.read_shell_command(
125 $initial_value = external_content_handlers.get(mime_type));
126 shell_command_with_argument_blind(cmd, ctx.launcher.source.spec, $cwd = cwd);
129 function content_handler_copy_url (ctx) {
130 ctx.abort(); // abort download
131 let uri = ctx.launcher.source.spec;
132 writeToClipboard(uri);
133 ctx.window.minibuffer.message("Copied: " + uri);
136 function content_handler_view_internally (ctx) {
137 var suggested_type = ctx.launcher.MIMEInfo.MIMEType;
138 if (viewable_mime_type_list.indexOf(suggested_type) == -1)
139 suggested_type = "text/plain";
140 var mime_type = yield ctx.window.minibuffer.read_viewable_mime_type(
141 $prompt = "View internally as",
142 $initial_value = suggested_type,
144 ctx.abort(); // abort before reloading
145 override_mime_type_for_next_load(ctx.launcher.source, mime_type);
146 ctx.frame.location = ctx.launcher.source.spec; // reload
149 function content_handler_view_as_text (ctx) {
150 ctx.abort(); // abort before reloading
151 override_mime_type_for_next_load(ctx.launcher.source, "text/plain");
152 ctx.frame.location = ctx.launcher.source.spec; // reload
155 function content_handler_prompt (ctx) {
156 var action_chosen = false;
157 var can_view_internally = ctx.frame != null &&
158 can_override_mime_type_for_uri(ctx.launcher.source);
161 panel = create_info_panel(ctx.window, "download-panel",
162 [["downloading", "Downloading:", ctx.launcher.source.spec],
163 ["mime-type", "Mime type:", ctx.launcher.MIMEInfo.MIMEType]]);
164 var action = yield ctx.window.minibuffer.read_single_character_option(
165 $prompt = "Action to perform: (s: save; o: open; O: open URL; c: copy URL; " +
166 (can_view_internally ? "i: view internally; t: view as text)" : ")"),
167 $options = (can_view_internally ? ["s", "o", "O", "c", "i", "t"] : ["s", "o", "O", "c"]));
170 yield content_handler_save(ctx);
171 action_chosen = true;
174 yield content_handler_open(ctx);
175 action_chosen = true;
178 yield content_handler_open_url(ctx);
179 action_chosen = true;
182 yield content_handler_copy_url(ctx);
183 action_chosen = true;
186 yield content_handler_view_internally(ctx);
187 action_chosen = true;
190 yield content_handler_view_as_text(ctx);
191 action_chosen = true;
195 handle_interactive_error(ctx.window, e);
206 * download_helper implements nsIHelperAppLauncherDialog.
208 * Sometimes, like when following a link, the content type of the document
209 * cannot be displayed by Mozilla. When this happens, Mozilla calls the
210 * `show' method of our download_helper with a handle for the started
211 * download and other contextual information.
213 function download_helper () {}
214 download_helper.prototype = {
215 constructor: download_helper,
216 QueryInterface: generate_QI(Ci.nsIHelperAppLauncherDialog,
217 Ci.nsIWebProgressListener2),
218 show: function (launcher, context, reason) {
219 var ctx = new content_handler_context(launcher, context);
221 ctx.abort(); //XXX: impolite; need better solution.
225 // is there anything in content_handlers for this object?
226 var mime_type = launcher.MIMEInfo.MIMEType;
227 var action = content_handlers.get(mime_type) ||
228 content_handler_prompt;
229 co_call(action(ctx));
231 handle_interactive_error(ctx.window, e);
234 promptForSaveToFile: function (launcher, context, default_file, suggested_file_extension) {
239 provide("content-handler");