1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is MozMill Test code.
16 * The Initial Developer of the Original Code is Mozilla Foundation.
17 * Portions created by the Initial Developer are Copyright (C) 2009
18 * the Initial Developer. All Rights Reserved.
21 * Henrik Skupin <hskupin@mozilla.com>
22 * Anthony Hughes <anthony.s.hughes@gmail.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 * The DownloadsAPI adds support for download related functions. It also gives
41 * access to the Download Manager.
46 // Include required modules
47 var utils = require("utils");
49 const gTimeout = 5000;
52 * List of available download states
54 const downloadState = {
71 function downloadManager() {
72 this._controller = null;
73 this.downloadState = downloadState;
75 this._dms = Cc["@mozilla.org/download-manager;1"].
76 getService(Ci.nsIDownloadManager);
80 * Download Manager class
82 downloadManager.prototype = {
84 * Returns the controller of the current window
86 * @returns Mozmill Controller
87 * @type {MozMillController}
90 return this._controller;
94 * Returns the number of currently active downloads
96 * @returns Number of active downloads
99 get activeDownloadCount() {
100 return this._dms.activeDownloadCount;
104 * Cancel all active downloads
106 cancelActiveDownloads : function downloadManager_cancelActiveDownloads() {
107 // Get a list of all active downloads (nsISimpleEnumerator)
108 var downloads = this._dms.activeDownloads;
110 // Iterate through each active download and cancel it
111 while (downloads.hasMoreElements()) {
112 var download = downloads.getNext().QueryInterface(Ci.nsIDownload);
113 this._dms.cancelDownload(download.id);
118 * Remove all downloads from the database
120 cleanUp : function downloadManager_cleanUp()
126 * Cancel any active downloads, remove the files, and clean
127 * up the Download Manager database
129 * @param {Array of download} downloads
130 * Downloaded files which should be deleted (optional)
132 cleanAll : function downloadManager_cleanAll(downloads) {
133 // Cancel any active downloads
134 this.cancelActiveDownloads();
136 // If no downloads have been specified retrieve the list from the database
137 if (downloads === undefined || downloads.length == 0)
138 downloads = this.getAllDownloads();
140 downloads = downloads.concat(this.getAllDownloads());
142 // Delete all files referred to in the Download Manager
143 this.deleteDownloadedFiles(downloads);
145 // Clean any entries from the Download Manager database
150 * Close the download manager
152 * @param {boolean} force
153 * Force the closing of the DM window
155 close : function downloadManager_close(force) {
156 var windowCount = mozmill.utils.getWindows().length;
158 if (this._controller) {
159 // Check if we should force the closing of the DM window
161 this._controller.window.close();
163 var cmdKey = utils.getEntity(this.getDtds(), "cmd.close.commandKey");
164 this._controller.keypress(null, cmdKey, {accelKey: true});
167 this._controller.waitForEval("subject.getWindows().length == " + (windowCount - 1),
168 gTimeout, 100, mozmill.utils);
169 this._controller = null;
174 * Delete all downloads from the local drive
176 * @param {download} downloads
177 * List of downloaded files
179 deleteDownloadedFiles : function downloadManager_deleteDownloadedFiles(downloads) {
180 downloads.forEach(function(download) {
182 var file = getLocalFileFromNativePathOrUrl(download.target);
190 * Get the list of all downloaded files in the database
192 * @returns List of downloads
193 * @type {Array of download}
195 getAllDownloads : function downloadManager_getAllDownloads() {
196 var dbConn = this._dms.DBConnection;
199 if (dbConn.schemaVersion < 3)
202 // Run a SQL query and iterate through all results which have been found
204 stmt = dbConn.createStatement("SELECT * FROM moz_downloads");
205 while (stmt.executeStep()) {
207 id: stmt.row.id, name: stmt.row.name, target: stmt.row.target,
208 tempPath: stmt.row.tempPath, startTime: stmt.row.startTime,
209 endTime: stmt.row.endTime, state: stmt.row.state,
210 referrer: stmt.row.referrer, entityID: stmt.row.entityID,
211 currBytes: stmt.row.currBytes, maxBytes: stmt.row.maxBytes,
212 mimeType : stmt.row.mimeType, autoResume: stmt.row.autoResume,
213 preferredApplication: stmt.row.preferredApplication,
214 preferredAction: stmt.row.preferredAction
223 * Gets the download state of the given download
225 * @param {ElemBase} download
226 * Download which state should be checked
228 getDownloadState : function downloadManager_getDownloadState(download) {
229 return download.getNode().getAttribute('state');
233 * Gets all the needed external DTD urls as an array
235 * @returns Array of external DTD urls
238 getDtds : function downloadManager_getDtds() {
239 var dtds = ["chrome://browser/locale/browser.dtd",
240 "chrome://mozapps/locale/downloads/downloads.dtd"];
245 * Retrieve an UI element based on the given spec
247 * @param {object} spec
248 * Information of the UI element which should be retrieved
249 * type: General type information
250 * subtype: Specific element or property
251 * value: Value of the element or property
252 * @returns Element which has been created
255 getElement : function downloadManager_getElement(spec) {
260 * subtype: subtype of property to match
261 * value: value of property to match
264 // Use a temporary lookup to get the download item
265 var download = new elementslib.Lookup(this._controller.window.document,
266 '/id("downloadManager")/id("downloadView")/' +
267 '{"' + spec.subtype + '":"' + spec.value + '"}');
268 this._controller.waitForElement(download, gTimeout);
270 // Use its download id to construct the real lookup expression
271 elem = new elementslib.Lookup(this._controller.window.document,
272 '/id("downloadManager")/id("downloadView")/' +
273 'id("' + download.getNode().getAttribute('id') + '")');
277 * subtype: Identifier of the specified download button (cancel, pause, resume, retry)
278 * value: Entry (download) of the download list
280 case "download_button":
281 // XXX: Bug 555347 - There are outstanding events to process
282 this._controller.sleep(0);
284 elem = new elementslib.Lookup(this._controller.window.document, spec.value.expression +
285 '/anon({"flex":"1"})/[1]/[1]/{"cmd":"cmd_' + spec.subtype + '"}');
288 throw new Error(arguments.callee.name + ": Unknown element type - " + spec.type);
295 * Open the Download Manager
297 * @param {MozMillController} controller
298 * MozMillController of the window to operate on
299 * @param {boolean} shortcut
300 * If true the keyboard shortcut is used
302 open : function downloadManager_open(controller, shortcut) {
304 if (mozmill.isLinux) {
305 var cmdKey = utils.getEntity(this.getDtds(), "downloadsUnix.commandkey");
306 controller.keypress(null, cmdKey, {ctrlKey: true, shiftKey: true});
308 var cmdKey = utils.getEntity(this.getDtds(), "downloads.commandkey");
309 controller.keypress(null, cmdKey, {accelKey: true});
312 controller.click(new elementslib.Elem(controller.menus["tools-menu"].menu_openDownloads));
315 controller.sleep(500);
316 this.waitForOpened(controller);
320 * Wait for the given download state
322 * @param {MozMillController} controller
323 * MozMillController of the window to operate on
324 * @param {downloadState} state
325 * Expected state of the download
326 * @param {number} timeout
327 * Timeout for waiting for the download state (optional)
329 waitForDownloadState : function downloadManager_waitForDownloadState(download, state, timeout) {
330 this._controller.waitForEval("subject.manager.getDownloadState(subject.download) == subject.state", timeout, 100,
331 {manager: this, download: download, state: state});
335 * Wait until the Download Manager has been opened
337 * @param {MozMillController} controller
338 * MozMillController of the window to operate on
340 waitForOpened : function downloadManager_waitForOpened(controller) {
341 this._controller = utils.handleWindow("type", "Download:Manager",
347 * Download the file of unkown type from the given location by saving it
348 * automatically to disk
350 * @param {MozMillController} controller
351 * MozMillController of the browser window
352 * @param {string} url
353 * URL of the file which has to be downloaded
355 var downloadFileOfUnknownType = function(controller, url) {
356 controller.open(url);
358 // Wait until the unknown content type dialog has been opened
359 controller.waitForEval("subject.getMostRecentWindow('').document.documentElement.id == 'unknownContentType'",
360 gTimeout, 100, mozmill.wm);
362 utils.handleWindow("type", "", function (controller) {
363 // Select to save the file directly
364 var saveFile = new elementslib.ID(controller.window.document, "save");
365 controller.waitThenClick(saveFile, gTimeout);
366 controller.waitForEval("subject.selected == true", gTimeout, 100,
369 // Wait until the OK button has been enabled and click on it
370 var button = new elementslib.Lookup(controller.window.document,
371 '/id("unknownContentType")/anon({"anonid":"buttons"})/{"dlgtype":"accept"}');
372 controller.waitForElement(button, gTimeout);
373 controller.waitForEval("subject.okButton.hasAttribute('disabled') == false", gTimeout, 100,
374 {okButton: button.getNode()});
375 controller.click(button);
380 * Get a local file from a native path or URL
382 * @param {string} aPathOrUrl
383 * Native path or URL of the file
384 * @see http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/downloads/content/downloads.js#1309
386 function getLocalFileFromNativePathOrUrl(aPathOrUrl) {
387 if (aPathOrUrl.substring(0,7) == "file://") {
388 // if this is a URL, get the file from that
389 let ioSvc = Cc["@mozilla.org/network/io-service;1"]
390 .getService(Ci.nsIIOService);
392 // XXX it's possible that using a null char-set here is bad
393 const fileUrl = ioSvc.newURI(aPathOrUrl, null, null)
394 .QueryInterface(Ci.nsIFileURL);
395 return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile);
397 // if it's a pathname, create the nsILocalFile directly
398 var f = new nsLocalFile(aPathOrUrl);
403 // Export of variables
404 exports.downloadState = downloadState;
406 // Export of functions
407 exports.downloadFileOfUnknownType = downloadFileOfUnknownType;
408 exports.getLocalFileFromNativePathOrUrl = getLocalFileFromNativePathOrUrl;
411 exports.downloadManager = downloadManager;