2 * (C) Copyright 2004-2007 Shawn Betts
3 * (C) Copyright 2007 John J. Foerch
4 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
6 * Use, modification, and distribution are subject to the terms specified in the
10 require("content-buffer.js");
11 require("load-spec.js");
12 require("suggest-file-name.js");
14 /* buffer is used only to associate with the download */
15 define_keywords("$use_cache", "$buffer", "$prepare_download", "$temp_file");
16 function save_uri (lspec, output_file) {
17 keywords(arguments, $use_cache = true);
19 var use_cache = arguments.$use_cache;
21 var buffer = arguments.$buffer;
23 var prepare_download = arguments.$prepare_download;
25 var download_file = output_file;
27 var temp_file = arguments.$temp_file;
28 if (temp_file === true) {
29 temp_file = Cc["@mozilla.org/file/local;1"]
30 .createInstance(Ci.nsILocalFile);
31 temp_file.initWithFile(output_file);
32 temp_file.leafName = "temp";
33 temp_file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
36 download_file = temp_file;
39 var uri = load_spec_uri(lspec);
40 var referrer_uri = load_spec_referrer(lspec);
41 var post_data = load_spec_post_data(lspec);
43 cache_key = load_spec_cache_key(lspec);
45 var file_uri = make_uri(download_file);
47 var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
48 .createInstance(Ci.nsIWebBrowserPersist);
50 persist.persistFlags =
51 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
52 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
53 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
56 persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
58 persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
60 var info = register_download(buffer, uri, download_file);
62 // We want this hook so that we run before the download buffer updates.
63 add_hook.call(info, "download_state_change_hook", function() {
64 if (info.state == DOWNLOAD_FINISHED) {
65 temp_file.moveTo(null, output_file.leafName);
66 info.target_file.leafName = output_file.leafName;
71 prepare_download(info);
73 var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
74 tr.init(uri, file_uri, output_file.leafName,
75 load_spec_mime_info(lspec),
76 null /* start time */,
79 persist.progressListener = tr;
80 persist.saveURI(uri, cache_key, referrer_uri, post_data,
81 null /* no extra headers */, file_uri,
82 null /* no privacy context */);
87 // We have no DOM, and can only save the URL as is.
88 const SAVEMODE_FILEONLY = 0x00;
89 // We have a DOM and can save as complete.
90 const SAVEMODE_COMPLETE_DOM = 0x01;
91 // We have a DOM which we can serialize as text.
92 const SAVEMODE_COMPLETE_TEXT = 0x02;
94 function get_save_mode_from_content_type (content_type) {
95 var mode = SAVEMODE_FILEONLY;
96 switch (content_type) {
98 case "application/xhtml+xml":
99 mode |= SAVEMODE_COMPLETE_TEXT;
102 case "application/xml":
103 mode |= SAVEMODE_COMPLETE_DOM;
109 define_keywords("$use_cache", "$buffer", "$wrap_column", "$prepare_download");
110 function save_document_as_text (document, output_file) {
111 keywords(arguments, $use_cache = true, $wrap_column = 80);
113 var mode = get_save_mode_from_content_type(document.contentType);
114 if (!(mode & SAVEMODE_COMPLETE_TEXT))
115 throw interactive_error("Document cannot be saved as text.");
117 var use_cache = arguments.$use_cache;
119 var prepare_download = arguments.$prepare_download;
121 var buffer = arguments.$buffer;
123 var uri = document.documentURIObject;
125 var file_uri = make_uri(output_file);
127 var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
128 .createInstance(Ci.nsIWebBrowserPersist);
130 persist.persistFlags =
131 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
132 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
133 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
136 Ci.nsIWebBrowserPersist.ENCODE_FLAGS_FORMATTED |
137 Ci.nsIWebBrowserPersist.ENCODE_FLAGS_ABSOLUTE_LINKS |
138 Ci.nsIWebBrowserPersist.ENCODE_FLAGS_NOFRAMES_CONTENT;
141 persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
143 persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
145 var info = register_download(buffer, uri);
146 if (prepare_download)
147 prepare_download(info);
149 var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
150 tr.init(uri, file_uri, output_file.leafName,
151 mime_info_from_mime_type("text/plain"),
152 null /* start time */,
153 null /* temp file */,
155 persist.progressListener = tr;
156 persist.saveDocument(document, file_uri, null /* data path */,
157 "text/plain", encoding_flags,
158 arguments.$wrap_column);
162 define_keywords("$use_cache", "$buffer", "$prepare_download");
163 function save_document_complete (document, output_file, output_dir) {
166 var mime_type = document.contentType;
168 var mode = get_save_mode_from_content_type(mime_type);
169 if (!(mode & SAVEMODE_COMPLETE_DOM))
170 throw interactive_error("Complete document cannot be saved.");
172 var use_cache = arguments.$use_cache;
174 var buffer = arguments.$buffer;
176 var prepare_download = arguments.$prepare_download;
178 var uri = document.documentURIObject;
180 var file_uri = make_uri(output_file);
182 var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
183 .createInstance(Ci.nsIWebBrowserPersist);
185 persist.persistFlags =
186 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
187 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
188 Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
191 Ci.nsIWebBrowserPersist.ENCODE_FLAGS_BASIC_ENTITIES;
194 persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
196 persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
199 var info = register_download(buffer, uri);
200 if (prepare_download)
201 prepare_download(info);
203 var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
204 tr.init(uri, file_uri, output_file.leafName,
205 mime_info_from_mime_type(mime_type),
206 null /* start time */,
207 null /* temp file */,
209 persist.progressListener = tr;
210 persist.saveDocument(document, file_uri, output_dir /* data path */,
211 mime_type, encoding_flags,
216 function download_failed_error () {
217 var e = new Error("Download failed");
218 e.__proto__ = download_failed_error.prototype;
221 download_failed_error.prototype.__proto__ = Error.prototype;
223 /* Returns an array of two elements: the first element is the
224 * nsILocalFile object, the second element is a boolean indicating
225 * whether the file is temporary and should be deleted when the caller is
228 define_keywords("$action", "$shell_command", "$shell_command_cwd", "$buffer", "$use_cache");
229 function download_as_temporary (lspec) {
230 keywords(arguments, $use_cache = true);
232 var action_description = arguments.$action;
233 var shell_command = arguments.$shell_command;
234 var shell_command_cwd = arguments.$shell_command_cwd;
236 var uri = load_spec_uri(lspec);
237 // If it is local file, there is no need to download it
238 if (uri.scheme == "file") {
239 let file = uri.QueryInterface(Ci.nsIFileURL).file;
241 yield co_return([file, false /* not temporary */]);
244 var file = get_temporary_file(suggest_file_name(lspec));
246 var cc = yield CONTINUATION;
248 function handle_state_change (info) {
249 var state = info.state;
251 case DOWNLOAD_CANCELED:
252 case DOWNLOAD_FAILED:
253 info.remove(); // ensure that the download cannot be retried later
255 // Delete the temporary file
256 file.remove(false /*non-recursive*/);
258 cc.throw(download_failed_error());
260 case DOWNLOAD_FINISHED:
261 cc([file, true /* temporary */]);
266 save_uri(lspec, file,
267 $use_cache = arguments.$use_cache,
268 $buffer = arguments.$buffer,
269 $prepare_download = function (info) {
270 if (action_description != null) {
271 info.action_description = action_description;
272 info.temporary_status = DOWNLOAD_TEMPORARY_FOR_ACTION;
273 } else if (shell_command != null) {
274 info.set_shell_command(shell_command, shell_command_cwd);
275 info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
277 add_hook.call(info, "download_state_change_hook", handle_state_change);
280 var result = yield SUSPEND;
281 yield co_return(result);