buffer.override_keymaps: dealt with privately inside buffer
[conkeror.git] / modules / save.js
blobe71f0511ebfa5cc29404988760affe8f40174ff8
1 /**
2  * (C) Copyright 2004-2007 Shawn Betts
3  * (C) Copyright 2007 John J. Foerch
4  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
5  *
6  * Use, modification, and distribution are subject to the terms specified in the
7  * COPYING file.
8 **/
10 in_module(null);
12 require("content-buffer.js");
13 require("load-spec.js");
14 require("suggest-file-name.js");
16 /* buffer is used only to associate with the download */
17 define_keywords("$use_cache", "$buffer", "$prepare_download", "$temp_file");
18 function save_uri (lspec, output_file) {
19     keywords(arguments, $use_cache = true);
21     var use_cache = arguments.$use_cache;
23     var buffer = arguments.$buffer;
25     var prepare_download = arguments.$prepare_download;
27     var download_file = output_file;
29     var temp_file = arguments.$temp_file;
30     if (temp_file === true) {
31         temp_file = Cc["@mozilla.org/file/local;1"]
32             .createInstance(Ci.nsILocalFile);
33         temp_file.initWithFile(output_file);
34         temp_file.leafName = "temp";
35         temp_file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
36     }
37     if (temp_file)
38         download_file = temp_file;
40     var cache_key = null;
41     var uri = load_spec_uri(lspec);
42     var referrer_uri = load_spec_referrer(lspec);
43     var post_data = load_spec_post_data(lspec);
44     if (use_cache)
45         cache_key = load_spec_cache_key(lspec);
47     var file_uri = make_uri(download_file);
49     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
50         .createInstance(Ci.nsIWebBrowserPersist);
52     persist.persistFlags =
53         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
54         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
55         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
57     if (use_cache)
58         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
59     else
60         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
62     var info = register_download(buffer, uri, download_file);
63     if (temp_file) {
64         // We want this hook so that we run before the download buffer updates.
65         add_hook.call(info, "download_state_change_hook", function() {
66             if (info.state == DOWNLOAD_FINISHED) {
67                 temp_file.moveTo(null, output_file.leafName);
68                 info.target_file.leafName = output_file.leafName;
69             }
70         });
71     }
72     if (prepare_download)
73         prepare_download(info);
75     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
76     tr.init(uri, file_uri, output_file.leafName,
77             load_spec_mime_info(lspec),
78             null /* start time */,
79             null /* temp file */,
80             persist);
81     persist.progressListener = tr;
82     persist.saveURI(uri, cache_key, referrer_uri, post_data, null /* no extra headers */, file_uri);
84     return info;
88 // We have no DOM, and can only save the URL as is.
89 const SAVEMODE_FILEONLY      = 0x00;
90 // We have a DOM and can save as complete.
91 const SAVEMODE_COMPLETE_DOM  = 0x01;
92 // We have a DOM which we can serialize as text.
93 const SAVEMODE_COMPLETE_TEXT = 0x02;
95 function get_save_mode_from_content_type (content_type) {
96     var mode = SAVEMODE_FILEONLY;
97     switch (content_type) {
98     case "text/html":
99     case "application/xhtml+xml":
100         mode |= SAVEMODE_COMPLETE_TEXT;
101         // Fall through
102     case "text/xml":
103     case "application/xml":
104         mode |= SAVEMODE_COMPLETE_DOM;
105         break;
106     }
107     return mode;
110 define_keywords("$use_cache", "$buffer", "$wrap_column", "$prepare_download");
111 function save_document_as_text (document, output_file) {
112     keywords(arguments, $use_cache = true, $wrap_column = 80);
114     var mode = get_save_mode_from_content_type(document.contentType);
115     if (!(mode & SAVEMODE_COMPLETE_TEXT))
116         throw interactive_error("Document cannot be saved as text.");
118     var use_cache = arguments.$use_cache;
120     var prepare_download = arguments.$prepare_download;
122     var buffer = arguments.$buffer;
124     var uri = document.documentURIObject;
126     var file_uri = make_uri(output_file);
128     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
129         .createInstance(Ci.nsIWebBrowserPersist);
131     persist.persistFlags =
132         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
133         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
134         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
136     var encoding_flags =
137         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_FORMATTED |
138         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_ABSOLUTE_LINKS |
139         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_NOFRAMES_CONTENT;
141     if (use_cache)
142         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
143     else
144         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
146     var info = register_download(buffer, uri);
147     if (prepare_download)
148         prepare_download(info);
150     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
151     tr.init(uri, file_uri, output_file.leafName,
152             mime_info_from_mime_type("text/plain"),
153             null /* start time */,
154             null /* temp file */,
155             persist);
156     persist.progressListener = tr;
157     persist.saveDocument(document, file_uri, null /* data path */,
158                          "text/plain", encoding_flags,
159                          arguments.$wrap_column);
160     return info;
163 define_keywords("$use_cache", "$buffer", "$prepare_download");
164 function save_document_complete (document, output_file, output_dir) {
165     keywords(arguments);
167     var mime_type = document.contentType;
169     var mode = get_save_mode_from_content_type(mime_type);
170     if (!(mode & SAVEMODE_COMPLETE_DOM))
171         throw interactive_error("Complete document cannot be saved.");
173     var use_cache = arguments.$use_cache;
175     var buffer = arguments.$buffer;
177     var prepare_download = arguments.$prepare_download;
179     var uri = document.documentURIObject;
181     var file_uri = make_uri(output_file);
183     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
184         .createInstance(Ci.nsIWebBrowserPersist);
186     persist.persistFlags =
187         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
188         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
189         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
191     var encoding_flags =
192         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_BASIC_ENTITIES;
194     if (use_cache)
195         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
196     else
197         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
200     var info = register_download(buffer, uri);
201     if (prepare_download)
202         prepare_download(info);
204     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
205     tr.init(uri, file_uri, output_file.leafName,
206             mime_info_from_mime_type(mime_type),
207             null /* start time */,
208             null /* temp file */,
209             persist);
210     persist.progressListener = tr;
211     persist.saveDocument(document, file_uri, output_dir /* data path */,
212                          mime_type, encoding_flags,
213                          0);
214     return info;
217 function download_failed_error () {
218     var e = new Error("Download failed");
219     e.__proto__ = download_failed_error.prototype;
220     return e;
222 download_failed_error.prototype.__proto__ = Error.prototype;
224 /* Returns an array of two elements: the first element is the
225  * nsILocalFile object, the second element is a boolean indicating
226  * whether the file is temporary and should be deleted when the caller is
227  * done with it.
228  */
229 define_keywords("$action", "$shell_command", "$shell_command_cwd", "$buffer", "$use_cache");
230 function download_as_temporary (lspec) {
231     keywords(arguments, $use_cache = true);
233     var action_description = arguments.$action;
234     var shell_command = arguments.$shell_command;
235     var shell_command_cwd = arguments.$shell_command_cwd;
237     var uri = load_spec_uri(lspec);
238     // If it is local file, there is no need to download it
239     if (uri.scheme == "file") {
240         let file = uri.QueryInterface(Ci.nsIFileURL).file;
242         yield co_return([file, false /* not temporary */]);
243     }
245     var file = get_temporary_file(suggest_file_name(lspec));
247     var cc = yield CONTINUATION;
249     function handle_state_change (info) {
250         var state = info.state;
251         switch (state) {
252         case DOWNLOAD_CANCELED:
253         case DOWNLOAD_FAILED:
254             info.remove(); // ensure that the download cannot be retried later
255             try {
256                 // Delete the temporary file
257                 file.remove(false /*non-recursive*/);
258             } catch (e) {}
259             cc.throw(download_failed_error());
260             break;
261         case DOWNLOAD_FINISHED:
262             cc([file, true /* temporary */]);
263             break;
264         }
265     }
267     save_uri(lspec, file,
268              $use_cache = arguments.$use_cache,
269              $buffer = arguments.$buffer,
270              $prepare_download = function (info) {
271                  if (action_description != null) {
272                      info.action_description = action_description;
273                      info.temporary_status = DOWNLOAD_TEMPORARY_FOR_ACTION;
274                  } else if (shell_command != null) {
275                      info.set_shell_command(shell_command, shell_command_cwd);
276                      info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
277                  }
278                  add_hook.call(info, "download_state_change_hook", handle_state_change);
279              });
281     var result = yield SUSPEND;
282     yield co_return(result);
285 provide("save");