Debian package: Declare compliance with Debian Policy 4.3.0
[conkeror.git] / modules / save.js
blobbf7063e2b077b06d6518a5a33509d9b1f1f523fd
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 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, parseInt("0666", 8));
34     }
35     if (temp_file)
36         download_file = temp_file;
38     var cache_key = null;
39     var uri = load_spec_uri(lspec);
40     var referrer_uri = load_spec_referrer(lspec);
41     var post_data = load_spec_post_data(lspec);
42     if (use_cache)
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;
55     if (use_cache)
56         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
57     else
58         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
60     var info = register_download(buffer, uri, download_file);
61     if (temp_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;
67             }
68         });
69     }
70     if (prepare_download)
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 */,
77             null /* temp file */,
78             persist, false);
79     persist.progressListener = tr;
81     if (version_compare(get_mozilla_version(), "36.0") >= 0) {
82         var channel = Cc["@mozilla.org/network/io-service;1"]
83             .getService(Components.interfaces.nsIIOService).newChannelFromURI(uri);
85         persist.saveURI(uri, cache_key, referrer_uri,
86                         // this arg was added in Gecko 36
87                         channel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE,
88                         post_data,
89                         null /* no extra headers */, file_uri,
90                         null /* no privacy context */);
91     } else {
92         persist.saveURI(uri, cache_key, referrer_uri, post_data,
93                         null /* no extra headers */, file_uri,
94                         null /* no privacy context */);
95     }
96     return info;
100 // We have no DOM, and can only save the URL as is.
101 const SAVEMODE_FILEONLY      = 0x00;
102 // We have a DOM and can save as complete.
103 const SAVEMODE_COMPLETE_DOM  = 0x01;
104 // We have a DOM which we can serialize as text.
105 const SAVEMODE_COMPLETE_TEXT = 0x02;
107 function get_save_mode_from_content_type (content_type) {
108     var mode = SAVEMODE_FILEONLY;
109     switch (content_type) {
110     case "text/html":
111     case "application/xhtml+xml":
112         mode |= SAVEMODE_COMPLETE_TEXT;
113         // Fall through
114     case "text/xml":
115     case "application/xml":
116         mode |= SAVEMODE_COMPLETE_DOM;
117         break;
118     }
119     return mode;
122 define_keywords("$use_cache", "$buffer", "$wrap_column", "$prepare_download");
123 function save_document_as_text (document, output_file) {
124     keywords(arguments, $use_cache = true, $wrap_column = 80);
126     var mode = get_save_mode_from_content_type(document.contentType);
127     if (!(mode & SAVEMODE_COMPLETE_TEXT))
128         throw interactive_error("Document cannot be saved as text.");
130     var use_cache = arguments.$use_cache;
132     var prepare_download = arguments.$prepare_download;
134     var buffer = arguments.$buffer;
136     var uri = document.documentURIObject;
138     var file_uri = make_uri(output_file);
140     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
141         .createInstance(Ci.nsIWebBrowserPersist);
143     persist.persistFlags =
144         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
145         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
146         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
148     var encoding_flags =
149         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_FORMATTED |
150         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_ABSOLUTE_LINKS |
151         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_NOFRAMES_CONTENT;
153     if (use_cache)
154         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
155     else
156         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
158     var info = register_download(buffer, uri);
159     if (prepare_download)
160         prepare_download(info);
162     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
163     tr.init(uri, file_uri, output_file.leafName,
164             mime_info_from_mime_type("text/plain"),
165             null /* start time */,
166             null /* temp file */,
167             persist, false);
168     persist.progressListener = tr;
169     persist.saveDocument(document, file_uri, null /* data path */,
170                          "text/plain", encoding_flags,
171                          arguments.$wrap_column);
172     return info;
175 define_keywords("$use_cache", "$buffer", "$prepare_download");
176 function save_document_complete (document, output_file, output_dir) {
177     keywords(arguments);
179     var mime_type = document.contentType;
181     var mode = get_save_mode_from_content_type(mime_type);
182     if (!(mode & SAVEMODE_COMPLETE_DOM))
183         throw interactive_error("Complete document cannot be saved.");
185     var use_cache = arguments.$use_cache;
187     var buffer = arguments.$buffer;
189     var prepare_download = arguments.$prepare_download;
191     var uri = document.documentURIObject;
193     var file_uri = make_uri(output_file);
195     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
196         .createInstance(Ci.nsIWebBrowserPersist);
198     persist.persistFlags =
199         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
200         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
201         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
203     var encoding_flags =
204         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_BASIC_ENTITIES;
206     if (use_cache)
207         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
208     else
209         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
212     var info = register_download(buffer, uri);
213     if (prepare_download)
214         prepare_download(info);
216     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
217     tr.init(uri, file_uri, output_file.leafName,
218             mime_info_from_mime_type(mime_type),
219             null /* start time */,
220             null /* temp file */,
221             persist, false);
222     persist.progressListener = tr;
223     persist.saveDocument(document, file_uri, output_dir /* data path */,
224                          mime_type, encoding_flags,
225                          0);
226     return info;
229 function download_failed_error () {
230     var e = new Error("Download failed");
231     e.__proto__ = download_failed_error.prototype;
232     return e;
234 download_failed_error.prototype.__proto__ = Error.prototype;
236 /* Returns an array of two elements: the first element is the
237  * nsILocalFile object, the second element is a boolean indicating
238  * whether the file is temporary and should be deleted when the caller is
239  * done with it.
240  */
241 define_keywords("$action", "$shell_command", "$shell_command_cwd", "$buffer", "$use_cache");
242 function download_as_temporary (lspec) {
243     keywords(arguments, $use_cache = true);
245     var action_description = arguments.$action;
246     var shell_command = arguments.$shell_command;
247     var shell_command_cwd = arguments.$shell_command_cwd;
249     var uri = load_spec_uri(lspec);
250     // If it is local file, there is no need to download it
251     if (uri.scheme == "file") {
252         let file = uri.QueryInterface(Ci.nsIFileURL).file;
254         return Promise.resolve([file, false /* not temporary */]);
255     }
257     var file = get_temporary_file(suggest_file_name(lspec));
259     var deferred = Promise.defer();
261     function handle_state_change (info) {
262         var state = info.state;
263         switch (state) {
264         case DOWNLOAD_CANCELED:
265         case DOWNLOAD_FAILED:
266             info.remove(); // ensure that the download cannot be retried later
267             try {
268                 // Delete the temporary file
269                 file.remove(false /*non-recursive*/);
270             } catch (e) {}
271             deferred.reject(download_failed_error());
272             break;
273         case DOWNLOAD_FINISHED:
274             deferred.resolve([file, true /* temporary */]);
275             break;
276         }
277     }
279     save_uri(lspec, file,
280              $use_cache = arguments.$use_cache,
281              $buffer = arguments.$buffer,
282              $prepare_download = function (info) {
283                  if (action_description != null) {
284                      info.action_description = action_description;
285                      info.temporary_status = DOWNLOAD_TEMPORARY_FOR_ACTION;
286                  } else if (shell_command != null) {
287                      info.set_shell_command(shell_command, shell_command_cwd);
288                      info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
289                  }
290                  add_hook.call(info, "download_state_change_hook", handle_state_change);
291              });
293     // FIXME: add cancelation support: tricky to handle cancelation coming before download starts
294     return deferred.promise;
297 provide("save");