Revamped and simplified load_spec infrastructure
[conkeror.git] / modules / save.js
blob51d5a6dd419a84f1534c5f3a8e7a59257d71f89c
1 require("content-buffer.js");
2 require("load-spec.js");
3 require("suggest-file-name.js");
5 /* buffer is used only to associate with the download */
6 define_keywords("$use_cache", "$buffer", "$prepare_download");
7 function save_uri(lspec, output_file) {
8     keywords(arguments, $use_cache = false);
10     var use_cache = arguments.$use_cache;
12     var buffer = arguments.$buffer;
14     var prepare_download = arguments.$prepare_download;
16     var cache_key = null;
17     var uri = load_spec_uri(lspec);
18     var referrer_uri = load_spec_referrer(lspec);
19     var post_data = load_spec_post_data(lspec);
20     if (use_cache)
21         cache_key = load_spec_cache_key(lspec);
23     var file_uri = makeFileURL(output_file);
25     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
27     persist.persistFlags =
28         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
29         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
30         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
32     if (use_cache)
33         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
34     else
35         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
37     var info = register_download(buffer, uri);
38     if (prepare_download)
39         prepare_download(info);
41     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
42     tr.init(uri, file_uri, output_file.leafName,
43             load_spec_mime_info(lspec),
44             null /* start time */,
45             null /* temp file */,
46             persist);
47     persist.progressListener = tr;
48     persist.saveURI(uri, cache_key, referrer_uri, post_data, null /* no extra headers */, file_uri);
50     return info;
54 // We have no DOM, and can only save the URL as is.
55 const SAVEMODE_FILEONLY      = 0x00;
56 // We have a DOM and can save as complete.
57 const SAVEMODE_COMPLETE_DOM  = 0x01;
58 // We have a DOM which we can serialize as text.
59 const SAVEMODE_COMPLETE_TEXT = 0x02;
61 function get_save_mode_from_content_type(content_type) {
62     var mode = SAVEMODE_FILEONLY;
63     switch (content_type) {
64     case "text/html":
65     case "application/xhtml+xml":
66         mode |= SAVEMODE_COMPLETE_TEXT;
67         // Fall through
68     case "text/xml":
69     case "application/xml":
70         mode |= SAVEMODE_COMPLETE_DOM;
71         break;
72     }
73     return mode;
76 define_keywords("$use_cache", "$buffer", "$wrap_column", "$prepare_download");
77 function save_document_as_text(document, output_file)
79     keywords(arguments, $use_cache = true, $wrap_column = 80);
81     var mode = get_save_mode_from_content_type(document.contentType);
82     if (!(mode & SAVEMODE_COMPLETE_TEXT))
83         throw interactive_error("Document cannot be saved as text.");
85     var use_cache = arguments.$use_cache;
87     var prepare_download = arguments.$prepare_download;
89     var buffer = arguments.$buffer;
91     var uri = document.documentURIObject;
93     var file_uri = makeFileURL(output_file);
95     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
97     persist.persistFlags =
98         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
99         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
100         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
102     var encoding_flags =
103         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_FORMATTED |
104         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_ABSOLUTE_LINKS |
105         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_NOFRAMES_CONTENT;
108     if (use_cache)
109         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
110     else
111         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
115     var info = register_download(buffer, uri);
116     if (prepare_download)
117         prepare_download(info);
119     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
120     tr.init(uri, file_uri, output_file.leafName,
121             mime_info_from_mime_type("text/plain"),
122             null /* start time */,
123             null /* temp file */,
124             persist);
125     persist.progressListener = tr;
126     persist.saveDocument(document, file_uri, null /* data path */,
127                          "text/plain", encoding_flags,
128                          arguments.$wrap_column);
129     return info;
132 define_keywords("$use_cache", "$buffer", "$prepare_download");
133 function save_document_complete(document, output_file, output_dir) {
135     var mime_type = document.contentType;
137     var mode = get_save_mode_from_content_type(mime_type);
138     if (!(mode & SAVEMODE_COMPLETE_DOM))
139         throw interactive_error("Complete document cannot be saved.");
141     var use_cache = arguments.$use_cache;
143     var buffer = arguments.$buffer;
145     var prepare_download = arguments.$prepare_download;
147     var uri = document.documentURIObject;
149     var file_uri = makeFileURL(output_file);
151     var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
153     persist.persistFlags =
154         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
155         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION |
156         Ci.nsIWebBrowserPersist.PERSIST_FLAGS_CLEANUP_ON_FAILURE;
158     var encoding_flags =
159         Ci.nsIWebBrowserPersist.ENCODE_FLAGS_BASIC_ENTITIES;
161     if (use_cache)
162         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE;
163     else
164         persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE;
167     var info = register_download(buffer, uri);
168     if (prepare_download)
169         prepare_download(info);
171     var tr = Cc["@mozilla.org/transfer;1"].createInstance(Ci.nsITransfer);
172     tr.init(uri, file_uri, output_file.leafName,
173             mime_info_from_mime_type(mime_type),
174             null /* start time */,
175             null /* temp file */,
176             persist);
177     persist.progressListener = tr;
178     persist.saveDocument(document, file_uri, output_dir /* data path */,
179                          mime_type, encoding_flags,
180                          0);
181     return info;
184 function download_failed_error() {
185     var e = new Error("Download failed");
186     e.__proto__ = download_failed_error.prototype;
187     return e;
189 download_failed_error.prototype.__proto__ = Error.prototype;
191 /* Returns an array of two elements: the first element is the 
192  * nsILocalFile object, the second element is a boolean indicating
193  * whether the file is temporary and should be deleted when the caller is
194  * done with it.
195  */
196 define_keywords("$action", "$shell_command", "$shell_command_cwd", "$buffer", "$use_cache");
197 function download_as_temporary(lspec) {
198     keywords(arguments, $use_cache = true);
200     var action_description = arguments.$action;
201     var shell_command = arguments.$shell_command;
202     var shell_command_cwd = arguments.$shell_command_cwd;
204     var uri = load_spec_uri(lspec);
205     // If it is local file, there is no need to download it
206     if (uri.scheme == "file")
207     {
208         let file = uri.QueryInterface(Ci.nsIFileURL).file;
210         yield co_return([file, false /* not temporary */]);
211     }
214     var file = get_temporary_file(suggest_file_name(lspec));
216     var cc = yield CONTINUATION;
218     function handle_state_change(info) {
219         var state = info.state;
220         switch (state) {
221         case DOWNLOAD_CANCELED:
222         case DOWNLOAD_FAILED:
223             info.remove(); // ensure that the download cannot be retried later
224             try {
225                 // Delete the temporary file
226                 file.remove(false /*non-recursive*/);
227             } catch (e) {}
228             cc.throw(download_failed_error());
229             break;
230         case DOWNLOAD_FINISHED:
231             cc([file, true /* temporary */]);
232             break;
233         }
234     }
236     save_uri(lspec, file,
237              $use_cache = arguments.$use_cache,
238              $buffer = arguments.$buffer,
239              $prepare_download = function (info) {
240                  if (action_description != null) {
241                      info.action_description = action_description;
242                      info.temporary_status = DOWNLOAD_TEMPORARY_FOR_ACTION;
243                  } else if (shell_command != null) {
244                      info.set_shell_command(shell_command, shell_command_cwd);
245                      info.temporary_status = DOWNLOAD_TEMPORARY_FOR_COMMAND;
246                  }
247                  add_hook.call(info, "download_state_change_hook", handle_state_change);
248              });
250     var result = yield SUSPEND;
251     yield co_return(result);