new module system
[conkeror.git] / modules / suggest-file-name.js
blobe957b59384c2e054832024aeae354ea9aa78f466
1 /**
2  * (C) Copyright 2007 John J. Foerch
3  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard.
4  *
5  * Portions of this file were derived from Mozilla,
6  * (C) Copyright 1998-2007 Mozilla Foundation.
7  *
8  * Use, modification, and distribution are subject to the terms specified in the
9  * COPYING file.
10 **/
12 in_module(null);
14 /* maybe_get_filename_extension
15  *
16  * file_name_s: string filename, may be null.
17  *
18  * returns null or extension part of file_name_s.
19  */
20 function maybe_get_filename_extension (file_name_s) {
21     var url = Components.classes["@mozilla.org/network/standard-url;1"]
22         .createInstance(Components.interfaces.nsIURL);
23     url.filePath = file_name_s;
24     if (url.fileExtension == '')
25         return null;
26     return url.fileExtension;
30 function maybe_get_url_extension (url_o) {
31     try {
32         var url = url_o.QueryInterface(Components.interfaces.nsIURL);
33         if (url.fileExtension == '')
34             return null;
35         return url.fileExtension;
36     } catch (e) {
37         return null;
38     }
41 /* maybe_get_preferred_filename_extension
42  *
43  * file_name_s: string filename, may be null.
44  *
45  * content_type: string content type, may be null.
46  *
47  * returns null, the default extension for the given
48  * content type, or the extension part of file_name_s.
49  */
50 function maybe_get_preferred_filename_extension (file_name_s, content_type) {
51     var ext = maybe_get_filename_extension (file_name_s);
52     var mimeInfo = null;
53     var primary = null;
54     if (content_type) {
55         try {
56             // throws if content_type is an empty string
57             mimeInfo = Components.classes["@mozilla.org/mime;1"]
58                 .getService(Components.interfaces.nsIMIMEService)
59                 .getFromTypeAndExtension(content_type, ext);
60             primary = mimeInfo.primaryExtension;
61         } catch (e) { }
62     }
63     if (ext && mimeInfo && mimeInfo.extensionExists(ext))
64         return ext;
65     else if (primary)
66         return primary;
67     else
68         return ext;
72 function maybe_get_preferred_url_extension (url_o, content_type) {
73     var ext = maybe_get_url_extension(url_o);
74     var mimeInfo = null;
75     var primary = null;
76     if (content_type) {
77         try {
78             mimeInfo = Components.classes["@mozilla.org/mime;1"]
79                 .getService(Components.interfaces.nsIMIMEService)
80                 .getFromTypeAndExtension(content_type, null);
81             primary = mimeInfo.primaryExtension;
82         } catch (e) { }
83     }
84     if (ext && mimeInfo && mimeInfo.extensionExists(ext))
85         return ext;
86     else if (primary)
87         return primary;
88     else
89         return ext;
92 function get_default_extension (file_name_s, url_o, content_type) {
93     if (content_type == "text/plain" ||
94         content_type == "application/octet-stream" ||
95         url_o.scheme == "ftp")
96     {
97         return "";
98     }
99     return (maybe_get_preferred_filename_extension(file_name_s, content_type) ||
100             maybe_get_preferred_url_extension(url_o, content_type));
103 function get_charset_for_save (doc) {
104     if (doc)
105         return doc.characterSet;
106     return null;
110 function maybe_filename_from_content_disposition (content_disposition, charset) {
111     if (content_disposition) {
112         const mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"]
113             .getService(Components.interfaces.nsIMIMEHeaderParam);
114         var dummy = { value: null };  // Need an out param...
116         var filename = null;
117         try {
118             filename = mhp.getParameter(content_disposition, "filename", charset, true, dummy);
119         } catch (e) {
120             try {
121                 filename = mhp.getParameter(content_disposition, "name", charset, true, dummy);
122             } catch (e) { }
123         }
124         if (filename)
125             return filename;
126         else
127             return null;
128     }
129     return null;
132 function maybe_filename_from_uri (uri) {
133     try {
134         var url = uri.QueryInterface(Components.interfaces.nsIURL);
135         if (url.fileName != "") {
136             // 2) Use the actual file name, if present
137             var text_to_sub_uri = Cc["@mozilla.org/intl/texttosuburi;1"].
138                 getService(Ci.nsITextToSubURI);
139             return text_to_sub_uri.unEscapeURIForUI(url.originCharset ||
140                                                     "UTF-8", url.fileName);
141         }
142     } catch (e) {
143         // This is something like a data: and so forth URI... no filename here.
144     }
145     return null;
148 function maybe_filename_from_title (title) {
149     if (title) {
150         title = title.replace(/^\s+|\s+$/g, "");
151         if (title && title.length > 0) {
152             // 3) Use the document title
153             return title;
154         }
155     }
156     return null;
159 function maybe_filename_from_url_last_directory (uri) {
160     // 5) If this is a directory, use the last directory name
161     try {
162         var path = uri.path.match(/\/([^\/]+)\/$/);
163         if (path && path.length > 1)
164             return path[1];
165         return null;
166     } catch (e) {
167         return null;
168     }
171 function maybe_filename_from_url_host (uri) {
172     if (uri && 'host' in uri)
173         return uri.host;
174     return null;
177 function maybe_filename_from_localization_default () {
178     try {
179         return getStringBundle().GetStringFromName("DefaultSaveFileName");
180     } catch (e) {
181         return null;
182     }
185 function generate_filename_safely_default (filename) {
186     return filename.replace(/[\/]+/g, '_');
189 function generate_filename_safely_darwin (filename) {
190     return filename.replace(/[\:\/]+/g, '_');
193 function generate_filename_safely_winnt (filename) {
194     filename = filename.replace(/[\"]+/g,     "'");
195     filename = filename.replace(/[\*\:\?]+/g, ' ');
196     filename = filename.replace(/[\<]+/g,     '(');
197     filename = filename.replace(/[\>]+/g,     ')');
198     filename = filename.replace(/[\\\/\|]+/g, '_');
199     return filename;
203 var generate_filename_safely_fn = null;
205 switch (get_os()) {
206 case 'Darwin':
207     generate_filename_safely_fn = generate_filename_safely_darwin;
208     break;
209 case 'WINNT':
210     generate_filename_safely_fn = generate_filename_safely_winnt;
211     break;
212 default:
213     generate_filename_safely_fn = generate_filename_safely_default;
214     break;
218  * spec may be a string (URI), a load spec, or an nsIDOMDocument
220  * extension may be null, in which case an extension is suggested as well
221  */
222 function suggest_file_name (spec, extension) {
223     var document;
224     var uri;
225     var content_type;
227     if (typeof(spec) == "string" || spec instanceof Ci.nsIDOMDocument)
228         spec = load_spec(spec);
230     var file_name = load_spec_filename(spec);
232     document = load_spec_document(spec);
233     uri = load_spec_uri(spec);
234     content_type = load_spec_mime_type(spec);
236     if (!file_name) {
237         file_name = generate_filename_safely_fn(
238             maybe_filename_from_content_disposition(
239                 document && get_document_content_disposition(document),
240                 get_charset_for_save(document)) ||
241             ((spec.suggest_filename_from_uri != false) && maybe_filename_from_uri(uri)) ||
242             maybe_filename_from_title(load_spec_title(spec)) ||
243             maybe_filename_from_url_last_directory(uri) ||
244             maybe_filename_from_url_host(uri) ||
245             maybe_filename_from_localization_default() ||
246             "index");
248     }
249     var base_name = file_name.replace(/\.[^.]*$/, "");
251     var file_ext = extension || load_spec_filename_extension(spec);
253     if (!file_ext) {
254         file_ext = get_default_extension(file_name, uri, content_type);
255         if (file_ext == "") {
256             let x = file_name.lastIndexOf(".");
257             if (x == -1)
258                 file_ext = null;
259             else
260                 file_ext = file_name.substring(x+1);
261         }
262         if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
263             content_type == "application/octet-stream")
264             file_ext = "html";
265     }
267     if (file_ext != null && file_ext.length > 0)
268         return base_name + "." + file_ext;
269     else
270         return base_name;
273 function suggest_save_path_from_file_name (file_name, buffer) {
274     var cwd = with_current_buffer(buffer, function (I) I.local.cwd);
275     var file = cwd.clone();
276     file.append(file_name);
277     return file.path;
280 provide("suggest-file-name");