diff --git a/LICENSE b/LICENSE
index 4072ac263..da2e7b6ab 100644
--- a/LICENSE
+++ b/LICENSE
@@ -7,7 +7,7 @@ DownThemAll! as a whole is licensed under GPL 2.0. See the GPL file.
Individual files may have additional and/or different licenses.
See the corresponding repository files available from
-
+
Most files are licensed under the GPL/LGPL-compatible MPL 2.0, or are
tri-licensed under a MPL 1.1/GPL 2.0/LGPL 2.1 license.
See the MPL, GPL, LGPL files respectively.
diff --git a/chrome/content/common/bindings.xml b/chrome/content/common/bindings.xml
index a474d45b3..7222f6f11 100644
--- a/chrome/content/common/bindings.xml
+++ b/chrome/content/common/bindings.xml
@@ -703,9 +703,9 @@
4) {
return ref;
@@ -805,7 +805,7 @@
if (l && poorMansSimilarity(newRef, ref) < 5) {
return newRef;
}
- return reccolor(newRef, ++l);
+ return arguments.callee(newRef, ++l);
})();
}
diff --git a/chrome/content/common/internalFunctions.js b/chrome/content/common/internalFunctions.js
index 0c0ea65af..3aaf70ae0 100644
--- a/chrome/content/common/internalFunctions.js
+++ b/chrome/content/common/internalFunctions.js
@@ -4,8 +4,8 @@
/* dTa-only code! - DO NOT include in overlays or such! */
"use strict";
-/* jshint browser:true */
-/* global _, Cc:true, Ci:true, Cu:true, Cr:true, ctor:true, Exception:true */
+/* jshint strict:true, globalstrict:true, browser:true */
+/* global _, Cc:true, Ci:true, Cr:true, Cu:true, ctor:true, Exception:true */
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
@@ -48,8 +48,7 @@ var getLargeIcon = (function() {
var getFavIcon = (function() {
const RE_HTML = /html?$|aspx?$|php\d?$|py$|\/[^.]*$/i;
return function getFavIcon(uri, cb, tp) {
- const path = uri.path || uri.pathQueryRef;
- if (!RE_HTML.test(path)) {
+ if (!RE_HTML.test(uri.path)) {
cb.call(tp, getIcon(uri), false);
return;
}
@@ -65,18 +64,18 @@ var getFavIcon = (function() {
* @return Either the element when there was just one parameter, or an array of
* elements.
*/
-function $(...args) {
- if (args.length === 1) {
- return document.getElementById(args[0]);
+function $() {
+ if (arguments.length === 1) {
+ return document.getElementById(arguments[0]);
}
let elements = [];
- for (let i = 0, e = args.length; i < e; ++i) {
- let element = document.getElementById(args[i]);
+ for (let i = 0, e = arguments.length; i < e; ++i) {
+ let element = document.getElementById(arguments[i]);
if (element) {
elements.push(element);
}
else {
- log(LOG_ERROR, "requested a non-existing element: " + args[i]);
+ log(LOG_ERROR, "requested a non-existing element: " + arguments[i]);
}
}
return elements;
@@ -207,7 +206,7 @@ var Utils = {
if (!isFinite(aNumber)) {
return 'NaN';
}
- return _('sizeKB', [aNumber.toFixed(decimalPlace || 1)]);
+ return _('sizeKB', [aNumber.toFixed(arguments.length > 1 ? decimalPlace : 1)]);
},
formatConflictName: function(basename, conflicts) {
@@ -228,8 +227,7 @@ var Utils = {
const sunits = units;
const nunits = sunits.length;
const s = scale;
- const {memoize} = require("support/memoize");
- return memoize(function(val, decimalPlace) {
+ return function(val, decimalPlace) {
var rv = val;
if (!isFinite(rv)) {
return 'NaN';
@@ -239,9 +237,9 @@ var Utils = {
rv /= 1024;
}
const unit = sunits[i];
- decimalPlace = isFinite(decimalPlace) ? decimalPlace : unit[1];
+ decimalPlace = arguments.length > 1 ? decimalPlace : unit[1];
return _(unit[0], [rv.toFixed(decimalPlace)], unit[2] && Math.floor(rv));
- }, 50);
+ };
}
Utils.formatBytes = createFormatter(
[['sizeB.2', 0, true], ['sizeKB', 1], ['sizeMB', 2], ['sizeGB', 2], ['sizeTB', 3]],
@@ -268,11 +266,11 @@ requireJoined(Utils, "support/stringfuncs");
*/
XPCOMUtils.defineLazyGetter(window, "_", function() {
let bundles = new Utils.StringBundles(document);
- return function(...args) {
- if (args.length === 1) {
- return bundles.getString(args[0]);
+ return function() {
+ if (arguments.length === 1) {
+ return bundles.getString(arguments[0]);
}
- return bundles.getFormattedString(...args);
+ return bundles.getFormattedString.apply(bundles, arguments);
};
});
diff --git a/chrome/content/dta/manager/conflicts.js b/chrome/content/dta/manager/conflicts.js
index 08e9a2053..07d5c2c53 100644
--- a/chrome/content/dta/manager/conflicts.js
+++ b/chrome/content/dta/manager/conflicts.js
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-/* jshint browser:true */
+/* jshint browser:true, globalstrict:true, strict:false */
/* global _, $ */
function load() {
@@ -24,3 +24,6 @@ function accept() {
}
return false;
}
+opener.addEventListener("unload", function unloadOpener() {
+ opener.removeEventListener("unload", unloadOpener, false);
+}, false);
diff --git a/chrome/content/dta/manager/info.js b/chrome/content/dta/manager/info.js
index 82a944ff0..c4de51b80 100644
--- a/chrome/content/dta/manager/info.js
+++ b/chrome/content/dta/manager/info.js
@@ -7,6 +7,8 @@
/* jshint strict:true, globalstrict:true, browser:true */
var {defer} = require("support/defer");
+var {TimerManager} = require("support/timers");
+var Timers = new TimerManager();
function discard() {
if (opener) {
@@ -184,6 +186,7 @@ var Dialog = {
},
unload: function() {
Tooltip.stop();
+ Timers.killAllTimers();
return true;
},
browseDir: function() {
diff --git a/chrome/content/dta/manager/manager.js b/chrome/content/dta/manager/manager.js
index 8e7d9962d..6b9f6b9d5 100644
--- a/chrome/content/dta/manager/manager.js
+++ b/chrome/content/dta/manager/manager.js
@@ -5,9 +5,10 @@
/* global _, DTA, $, $$, Utils, Preferences, getDefaultDownloadsDirectory, unloadWindow */
/* global $e, mapInSitu, filterMapInSitu, filterInSitu, mapFilterInSitu, setTimeoutOnlyFun */
/* global toURI, toURL, showPreferences, openUrl, getLargeIcon */
-/* global TreeManager, Prefs, ConflictManager */
+/* global Tree, Prefs */
/* global QUEUED, PAUSED, CANCELED, FINISHING, COMPLETE, RUNNING, SPEED_COUNT, REFRESH_FREQ, MIN_CHUNK_SIZE */
-/* jshint strict:true, globalstrict:true, browser:true, latedef:false */
+/* jshint strict:false, globalstrict:true, browser:true, latedef:false */
+/* jshint -W083, -W030 */
var {CoThreadListWalker} = require("support/cothreads");
var Prompts = require("prompts");
@@ -15,6 +16,7 @@ var {ByteBucket} = require("support/bytebucket");
var {GlobalBucket} = require("manager/globalbucket");
var {defer} = require("support/defer");
var PrivateBrowsing = require("support/pbm");
+var {TimerManager} = require("support/timers");
var {ContentHandling} = require("support/contenthandling");
var GlobalProgress = new (require("manager/globalprogress").GlobalProgress)(window);
var RequestManipulation = require("support/requestmanipulation");
@@ -30,6 +32,7 @@ var {Connection} = require("manager/connection");
var {createRenamer} = require("manager/renamer");
var {memoize, identity} = require("support/memoize");
var {moveFile} = require("support/movefile");
+var {Task} = requireJSM("resource://gre/modules/Task.jsm");
// Use the main OS.File here!
var {OS} = requireJSM("resource://gre/modules/osfile.jsm");
@@ -40,23 +43,14 @@ XPCOMUtils.defineLazyGetter(window, "AlertService", () => require("support/alert
XPCOMUtils.defineLazyGetter(window, "Decompressor", () => require("manager/decompressor").Decompressor);
XPCOMUtils.defineLazyGetter(window, "Verificator", () => require("manager/verificator"));
XPCOMUtils.defineLazyGetter(window, "FileExts", () => new FileExtensionSheet(window, Tree));
-XPCOMUtils.defineLazyGetter(window, "ConflictManager", () => {
- return new (require("manager/conflicts"))(
- window, Utils.formatConflictName.bind(Utils), Prefs, _);
-});
-
-let speedElems;
/* global TextCache_PAUSED, TextCache_QUEUED, TextCache_COMPLETE, TextCache_CANCELED, TextCache_NAS */
/* global TextCache_UNKNOWN, TextCache_OFFLINE, TextCache_TIMEOUT, TextCache_STARTING, TextCache_DECOMPRESSING */
-/* global TextCache_VERIFYING, TextCache_MOVING, TextCache_FINISHING */
+/* global TextCache_VERIFYING, TextCache_MOVING */
addEventListener("load", function load_textCache() {
removeEventListener("load", load_textCache, false);
- speedElems = $('listSpeeds', 'perDownloadSpeedLimitList');
const texts = ['paused', 'queued', 'complete', 'canceled', 'nas', 'unknown',
- 'offline', 'timeout', 'starting', 'decompressing', 'verifying', 'moving',
- 'finishing',
- ];
+ 'offline', 'timeout', 'starting', 'decompressing', 'verifying', 'moving'];
for (let i = 0, text; i < texts.length; ++i) {
text = texts[i];
window["TextCache_" + text.toUpperCase()] = _(text);
@@ -73,29 +67,22 @@ function isOSError(ex, unix, win) {
return false;
}
-function timeout(secs) {
- return new Promise(function(resolve) {
- setTimeoutOnlyFun(() => resolve(), secs);
- });
-}
-
function _moveFile(destination, self) {
let remakeDir = false;
- let move = async function() {
+ let move = function*() {
for (let x = 0; x < 10; ++x) {
if (remakeDir) {
- await Utils.makeDir(destination, Prefs.dirPermissions, true);
+ yield Utils.makeDir(destination, Prefs.dirPermissions, true);
}
let df = destination.clone();
df.append(self.destinationName);
try {
- await moveFile(self.tmpFile.path, df.path, self.shouldOverwrite);
+ yield moveFile(self.tmpFile.path, df.path, self.shouldOverwrite);
return;
}
catch (ex) {
if (isOSError(ex, "EEXIST", "ERROR_ALREADY_EXISTS") && !self.shouldOverwrite) {
self.conflicts += 1;
- x--;
continue;
}
if (isOSError(ex, "ENAMETOOLONG", "ERROR_PATH_NOT_FOUND")) {
@@ -114,13 +101,15 @@ function _moveFile(destination, self) {
remakeDir = true;
}
log(LOG_ERROR, ex);
- await timeout(x * 500);
+ yield new Promise(function(resolve) {
+ setTimeoutOnlyFun(() => resolve(), x * 500);
+ });
}
}
log(LOG_ERROR, "shit hit the fan!");
throw new Exception("Failed to move file");
};
- return move();
+ return Task.spawn(move);
};
function dieEarly() {
@@ -131,35 +120,7 @@ function dieEarly() {
}
window.addEventListener("unload", dieEarly, false);
-function _downloadChunk(download, chunk, header) {
- chunk.download = new Connection(download, chunk, header || download.mustGetInfo);
- chunk.running = true;
- download.mustGetInfo = false;
- download.setState(RUNNING);
- log(LOG_DEBUG, "started: " + chunk);
- ++download.activeChunks;
- ++download.sessionConnections;
-}
-function downloadNewChunk(download, start, end, header) {
- let chunk = new Chunk(download, start, end);
- download.chunks.push(chunk);
- download.chunks.sort(function(a,b) { return a.start - b.start; });
- _downloadChunk(download, chunk, header);
-}
-function downloadOldChunk(download, chunk, header) {
- if (chunk.wasOpened) {
- let idx = download.chunks.indexOf(chunk);
- if (idx < 0) {
- throw Error("Invalid chunk");
- }
- let newChunk = chunk.clone();
- download.chunks[idx] = newChunk;
- _downloadChunk(download, newChunk, header);
- }
- else {
- _downloadChunk(download, chunk, header);
- }
-}
+var Timers = new TimerManager();
var Dialog_loadDownloads_props =
['contentType', 'conflicts', 'postData', 'destinationName', 'resumable', 'compression',
@@ -172,7 +133,6 @@ var Dialog_serialize_props =
['fileName', 'fileNameFromUser', 'postData', 'description', 'title', 'resumable', 'mask', 'pathName',
'compression', 'contentType', 'conflicts', 'fromMetalink', 'speedLimit', "relaxSize", "cleanRequest"];
-var Tree;
var Dialog = {
_observes: [
'quit-application-requested',
@@ -216,7 +176,7 @@ var Dialog = {
_wasRunning: false,
_sum: 0,
_speeds: new SpeedStats(10),
- _running: new Set(),
+ _running: [],
_autoClears: [],
completed: 0,
finishing: 0,
@@ -307,7 +267,7 @@ var Dialog = {
}, false);
let tree = $("downloads");
- Tree = new TreeManager(tree);
+ Tree.init(tree);
addEventListener("unload", function unloadUnlink() {
removeEventListener("unload", unloadUnlink, false);
Tree.unlink();
@@ -488,7 +448,7 @@ var Dialog = {
$('listSpeeds').limit -= 102400;
this.changeSpeedLimit();
},
- _loadDownloads: async function() {
+ _loadDownloads: function() {
this._loading = $('loading');
if (!this._loading) {
this._loading = {};
@@ -499,53 +459,25 @@ var Dialog = {
log(LOG_INFO, "loading of the queue started!");
GlobalProgress.reset();
GlobalProgress.pause();
- try {
- let result = await QueueStore.loadItems();
- if (result && result.length) {
- log(LOG_INFO, "Result has arrived: " + result.length);
- await new Promise((resolve, reject) => {
- let loader = new CoThreadListWalker(
- this._loadDownloads_item,
- result,
- -1,
- this
- );
- loader.start(resolve);
- });
- }
- log(LOG_INFO, "Result was processed");
- }
- catch (ex) {
- log(LOG_ERROR, "Failed to load QueueStore items", ex);
- }
-
- Tree.savePositions();
- Tree.invalidate();
- Tree.doFilter();
- Tree.endUpdate();
-
- if (this._brokenDownloads.length) {
- QueueStore.beginUpdate();
- try {
- for (let id of this._brokenDownloads) {
- QueueStore.deleteDownload(id);
- log(LOG_ERROR, "Removed broken download #" + id);
- }
- }
- catch (ex) {
- log(LOG_ERROR, "failed to remove broken downloads", ex);
+ QueueStore.loadItems(function(result) {
+ if (!result || !result.length) {
+ log(LOG_DEBUG, "The cake is a lie");
+ this._loadDownloads_finish();
+ return;
}
- QueueStore.endUpdate();
- }
- delete this._brokenDownloads;
- delete this._loading;
-
- GlobalProgress.reset();
- this.statusText.hidden = false;
-
- this._timerProcess = setInterval(() => this.process(), REFRESH_FREQ);
- this.refresh();
- this.start();
+ log(LOG_INFO, "Result has arrived: " + result.length);
+ this._loader = new CoThreadListWalker(
+ this._loadDownloads_item,
+ result,
+ -1,
+ this
+ );
+ let self = this;
+ this._loader.start(function() {
+ result = null;
+ self._loadDownloads_finish();
+ });
+ }, this);
},
_loadDownloads_item: function(dbItem, idx) {
if (!idx) {
@@ -560,7 +492,7 @@ var Dialog = {
try {
let down = dbItem.item;
- let d = new QueueItem(Dialog);
+ let d = new QueueItem();
d.dbId = dbItem.id;
let state = Dialog_loadDownloads_get(down, "state");
if (state) {
@@ -581,7 +513,7 @@ var Dialog = {
}
// only access the setter of the last so that we don't generate stuff trice.
- d._pathName = identity(Utils.addFinalSlash(Dialog_loadDownloads_get(down, "pathName")));
+ d._pathName = identity(Dialog_loadDownloads_get(down, "pathName"));
d._description = identity(Dialog_loadDownloads_get(down, "description"));
d._title = identity(Dialog_loadDownloads_get(down, "title"));
d._mask = identity(Dialog_loadDownloads_get(down, "mask"));
@@ -674,6 +606,38 @@ var Dialog = {
}
return true;
},
+ _loadDownloads_finish: function() {
+ log(LOG_INFO, "Result was processed");
+ delete this._loader;
+ Tree.savePositions();
+ Tree.invalidate();
+ Tree.doFilter();
+ Tree.endUpdate();
+
+ if (this._brokenDownloads.length) {
+ QueueStore.beginUpdate();
+ try {
+ for (let id of this._brokenDownloads) {
+ QueueStore.deleteDownload(id);
+ log(LOG_ERROR, "Removed broken download #" + id);
+ }
+ }
+ catch (ex) {
+ log(LOG_ERROR, "failed to remove broken downloads", ex);
+ }
+ QueueStore.endUpdate();
+ }
+ delete this._brokenDownloads;
+ delete this._loading;
+
+ GlobalProgress.reset();
+ this.statusText.hidden = false;
+
+ this._updTimer = Timers.createRepeating(REFRESH_FREQ, this.process, this, true);
+ this.refresh();
+ this.start();
+ },
+
openAdd: function() {
window.openDialog(
'chrome://dta/content/dta/addurl.xul',
@@ -684,7 +648,7 @@ var Dialog = {
openDonate: function() {
try {
- openUrl('http://www.downthemall.net/howto/donate/');
+ openUrl('https://www.downthemall.org/howto/donate/');
}
catch(ex) {
window.alert(ex);
@@ -710,8 +674,8 @@ var Dialog = {
this.run(d);
}
}
- this._timerWritten = setInterval(() => this.refreshWritten(), 200);
- this._timerSave = setInterval(() => this.saveRunning(), 10000);
+ Timers.createRepeating(200, this.refreshWritten, this, true);
+ Timers.createRepeating(10000, this.saveRunning, this);
$('loadingbox').parentNode.removeChild($('loadingbox'));
window.removeEventListener("unload", dieEarly, false);
@@ -740,7 +704,7 @@ var Dialog = {
}
},
_continueReinit: function() {
- this._running = new Set();
+ this._running = [];
delete this._forceQuit;
this._speeds.clear();
this.offlineForced = false;
@@ -802,7 +766,8 @@ var Dialog = {
refresh: function() {
try {
const now = Utils.getTimestamp();
- for (let d of this._running) {
+ for (let i = 0, e = this._running.length; i < e; ++i) {
+ let d = this._running[i];
if (!d) {
continue;
}
@@ -830,7 +795,7 @@ var Dialog = {
this._speeds.add(this._sum, now);
let speed = Utils.formatSpeed(this._speeds.avg);
this._maxObservedSpeed = Math.max(this._speeds.avg || this._maxObservedSpeed, this._maxObservedSpeed);
- for (let e of speedElems) {
+ for (let e of $('listSpeeds', 'perDownloadSpeedLimitList')) {
try {
e.hint = this._maxObservedSpeed;
hintChunkBufferSize(this._maxObservedSpeed);
@@ -842,8 +807,8 @@ var Dialog = {
// Refresh status bar
this.statusText.label = _("currentdownloadstats",
- [this.completed, Tree.downloadCount, Tree.rowCount, this._running.size]);
- if (!this._running.size) {
+ [this.completed, Tree.downloadCount, Tree.rowCount, this._running.length]);
+ if (!this._running.length) {
this.statusSpeed.hidden = true;
}
else {
@@ -852,11 +817,10 @@ var Dialog = {
}
// Refresh window title
- let fr = this._running.values().next().value || null;
- if (this._running.size === 1 && fr.totalSize > 0) {
+ if (this._running.length === 1 && this._running[0].totalSize > 0) {
if (Tree.filtered) {
document.title = _('titlespeedfiltered', [
- fr.percent,
+ this._running[0].percent,
this.statusSpeed.label,
this.completed,
Tree.downloadCount,
@@ -865,20 +829,20 @@ var Dialog = {
}
else {
document.title = _('titlespeed', [
- fr.percent,
+ this._running[0].percent,
this.statusSpeed.label,
this.completed,
Tree.downloadCount,
]);
}
- if (fr.totalSize) {
- GlobalProgress.activate(fr.progress * 10, 1000);
+ if (this._running[0].totalSize) {
+ GlobalProgress.activate(this._running[0].progress * 10, 1000);
}
else {
GlobalProgress.unknown();
}
}
- else if (this._running.size > 0) {
+ else if (this._running.length > 0) {
let p = Math.floor(this.completed * 1000 / Tree.downloadCount);
let pt = Math.floor(this.completed * 100 / Tree.downloadCount) + '%';
if (Tree.filtered) {
@@ -950,7 +914,8 @@ var Dialog = {
}
},
refreshWritten: function() {
- for (let d of this._running) {
+ for (let i = 0, e = this._running.length; i < e; ++i) {
+ let d = this._running[i];
if (!d) {
continue;
}
@@ -959,11 +924,11 @@ var Dialog = {
}
},
saveRunning: function() {
- if (!this._running.size) {
+ if (!this._running.length) {
return;
}
- for (let d of this._running) {
- d.save();
+ for (let i = 0, e = this._running.length; i < e; ++i) {
+ this._running[i].save();
}
},
@@ -990,17 +955,14 @@ var Dialog = {
Tree.box.invalidate();
},
- _filterAutoRetrying(d) {
- return !d.autoRetry();
- },
-
process: function() {
try {
Prefs.refreshConnPrefs(this._running);
this.refresh();
let ts = Utils.getTimestamp();
- for (let d of this._running) {
+ for (let i = 0, e = this._running.length; i < e; ++i) {
+ let d = this._running[i];
if (!d || d.isCritical) {
continue;
}
@@ -1021,7 +983,7 @@ var Dialog = {
if (!this.offline && !this._mustReload) {
if (Prefs.autoRetryInterval) {
- filterInSitu(this._autoRetrying, this._filterAutoRetrying);
+ filterInSitu(this._autoRetrying, d => !d.autoRetry());
}
this.startNext();
}
@@ -1049,7 +1011,7 @@ var Dialog = {
try {
var rv = false;
// pre-condition, do check prior to loop, or else we'll have the generator cost.
- if (this._running.size >= Prefs.maxInProgress) {
+ if (this._running.length >= Prefs.maxInProgress) {
return false;
}
if (Prefs.schedEnabled) {
@@ -1082,7 +1044,7 @@ var Dialog = {
log(LOG_DEBUG, "rebuild scheduler");
}
let finishingPenality = Math.ceil(this.finishing / 10);
- while (this._running.size < Prefs.maxInProgress - finishingPenality) {
+ while (this._running.length < Prefs.maxInProgress - finishingPenality) {
let d = this.scheduler.next(this._running);
if (!d) {
break;
@@ -1123,8 +1085,7 @@ var Dialog = {
if (download.totalSize) {
download.partialSize = download.totalSize;
}
- log(LOG_INFO,
- "Download seems to be complete; likely a left-over from a crash, finish it:" + download);
+ log(LOG_INFO, "Download seems to be complete; likely a left-over from a crash, finish it:" + download);
download.finishDownload();
return true;
}
@@ -1140,13 +1101,16 @@ var Dialog = {
else {
log(LOG_INFO, "Let's resume " + download + " at " + download.partialSize);
}
- this._running.add(download);
+ this._running.push(download);
download.prealloc();
download.resumeDownload();
return true;
},
wasStopped: function(download) {
- this._running.delete(download);
+ let idx = this._running.indexOf(download);
+ if (idx > -1) {
+ this._running.splice(idx, 1);
+ }
},
wasFinished: function() {
--this.finishing;
@@ -1223,8 +1187,11 @@ var Dialog = {
}
},
wasRemoved: function(download) {
- this._running.delete(download);
- let idx = this._autoRetrying.indexOf(download);
+ let idx = this._running.indexOf(download);
+ if (idx > -1) {
+ this._running.splice(idx, 1);
+ }
+ idx = this._autoRetrying.indexOf(download);
if (idx > -1) {
this._autoRetrying.splice(idx, 1);
}
@@ -1282,9 +1249,9 @@ var Dialog = {
// stop everything!
// enumerate everything we'll have to wait for!
- if (this._timerProcess) {
- clearInterval(this._timerProcess);
- delete this._timerProcess;
+ if (this._updTimer) {
+ Timers.killTimer(this._updTimer);
+ delete this._updTimer;
}
let chunks = 0;
@@ -1317,7 +1284,7 @@ var Dialog = {
if (chunks || finishing) {
if (!this._forceClose && this._safeCloseAttempts < 20) {
++this._safeCloseAttempts;
- setTimeoutOnlyFun(() => this.shutdown(callback), 250);
+ Timers.createOneshot(250, () => this.shutdown(callback), this);
return false;
}
log(LOG_ERROR, "Going down even if queue was not probably closed yet!");
@@ -1360,9 +1327,10 @@ var Dialog = {
unload: function() {
Limits.killServerBuckets();
- clearInterval(this._timerRunning);
- clearInterval(this._timerSave);
- clearInterval(this._timerProcess);
+ Timers.killAllTimers();
+ if (this._loader) {
+ this._loader.cancel();
+ }
Prefs.shutdown();
try {
this._cleanTmpDir();
@@ -1469,47 +1437,62 @@ var Metalinker = {
};
requireJoined(Metalinker, "support/metalinker");
-var QueueItem = class QueueItem {
- constructor(dialog) {
- this.dialog = dialog;
-
- this.visitors = new VisitorManager();
- this.chunks = [];
- this.speeds = new SpeedStats(SPEED_COUNT);
- this.rebuildDestination_renamer = createRenamer(this);
- }
-
- get maskURL() {
- return this.urlManager.usableURL;
- }
-
- get maskCURL() {
- return Utils.getCURL(this.maskURL);
- }
-
- get maskURLPath() {
- return this.urlManager.usableURLPath;
- }
-
- get maskReferrerURL() {
- return this.referrerUrlManager.usableURL;
- }
-
- get maskReferrerURLPath() {
- return this.referrerUrlManager.usableURLPath;
- }
+function QueueItem() {
+ this.visitors = new VisitorManager();
- get maskReferrerCURL() {
- return Utils.getCURL(this.maskReferrerURL);
- }
+ this.chunks = [];
+ this.speeds = new SpeedStats(SPEED_COUNT);
+ this.rebuildDestination_renamer = createRenamer(this);
+}
- get autoRetrying() {
- return !!this._autoRetryTime;
- }
+QueueItem.prototype = {
+ state: QUEUED,
+ _setStateInternal: function(nv) {
+ Object.defineProperty(this, "state", {value: nv, configurable: true, enumerable: true});
+ },
+ setState: function(nv) {
+ if (this.state === nv) {
+ return nv;
+ }
+ if (this.state === RUNNING) {
+ // remove ourself from inprogresslist
+ Dialog.wasStopped(this);
+ // kill the bucket via it's setter
+ this.bucket = null;
+ }
+ else if (this.state === COMPLETE) {
+ --Dialog.completed;
+ }
+ else if (this.state === FINISHING) {
+ --Dialog.finishing;
+ }
+ this.speed = '';
+ this._setStateInternal(nv);
+ if (this.state === RUNNING) {
+ // set up the bucket
+ this._bucket = new ByteBucket(this.speedLimit, 1.7, "download");
+ }
+ else if (this.state === FINISHING) {
+ ++Dialog.finishing;
+ if (!this.totalSize) {
+ // We are done now, just set indeterminate size downloads to what we actually downloaded
+ this.refreshPartialSize();
+ this.totalSize = this.partialSize;
+ }
+ }
+ else if (this.state === COMPLETE) {
+ ++Dialog.completed;
+ }
+ Dialog.signal(this);
+ this.invalidate();
+ Tree.refreshTools();
+ return nv;
+ },
+ _bucket: null,
get bucket() {
return this._bucket;
- }
+ },
set bucket(nv) {
if (nv !== null) {
throw new Exception("Bucket is only nullable");
@@ -1517,11 +1500,12 @@ var QueueItem = class QueueItem {
if (this._bucket) {
this._bucket = null;
}
- }
+ },
+ _speedLimit: -1,
get speedLimit() {
return this._speedLimit;
- }
+ },
set speedLimit(nv) {
nv = Math.max(nv, -1);
if (this._speedLimit === nv) {
@@ -1532,11 +1516,20 @@ var QueueItem = class QueueItem {
this._bucket.byteRate = this.speedLimit;
}
this.save();
- }
+ },
+ otherBytes: 0,
+
+ postData: null,
+
+ fromMetalink: false,
+ bNum: 0,
+ iNum: 0,
+ _fileName: null,
+ fileNameFromUser: false,
get fileName() {
return this._fileName;
- }
+ },
set fileName(nv) {
if (this._fileName === nv || this.fileNameFromUser) {
return nv;
@@ -1547,8 +1540,36 @@ var QueueItem = class QueueItem {
this.rebuildDestination();
this.invalidate(0);
return nv;
- }
-
+ },
+ setUserFileName: function(name) {
+ try {
+ Tree.beginUpdate();
+ this.fileNameFromUser = false;
+ this.fileName = name;
+ this.fileNameFromUser = true;
+ this.save();
+ }
+ finally {
+ this.iconProp; // set up initial icon to avoid display problems
+ Tree.invalidate();
+ Tree.endUpdate();
+ }
+ },
+ shortenName: function() {
+ let fn = this.destinationName;
+ let ext = Utils.getExtension(fn);
+ if (ext) {
+ fn = fn.substring(0, fn.length - ext.length - 1);
+ }
+ let nn = fn.substr(0, Math.min(200, Math.max(fn.length - 25, 10)));
+ if (nn === fn) {
+ return;
+ }
+ if (ext) {
+ nn += "." + ext;
+ }
+ this.destinationName = nn;
+ },
get fileNameAndExtension() {
if (!this._fileNameAndExtension) {
let fn = this.fileName;
@@ -1577,15 +1598,13 @@ var QueueItem = class QueueItem {
this._fileNameAndExtension = {name: fn, extension: ext };
}
return this._fileNameAndExtension;
- }
-
+ },
get referrerUrlManager() {
if (this.referrer && !this._referrerUrlManager) {
this._referrerUrlManager = new UrlManager([this.referrer]);
}
return this._referrerUrlManager;
- }
-
+ },
get referrerFileNameAndExtension() {
if (!this.referrerUrlManager) {
return null;
@@ -1602,11 +1621,11 @@ var QueueItem = class QueueItem {
this._referrerFileNameAndExtension = {name: fn, extension: ext};
}
return this._referrerFileNameAndExtension;
- }
-
+ },
+ _description: null,
get description() {
return this._description;
- }
+ },
set description(nv) {
if (nv === this._description) {
return nv;
@@ -1615,11 +1634,11 @@ var QueueItem = class QueueItem {
this.rebuildDestination();
this.invalidate(0);
return nv;
- }
-
+ },
+ _title: '',
get title() {
return this._title;
- }
+ },
set title(nv) {
if (nv === this._title) {
return this._title;
@@ -1628,25 +1647,26 @@ var QueueItem = class QueueItem {
this.rebuildDestination();
this.invalidate(0);
return this._title;
- }
-
+ },
+ _pathName: null,
get pathName() {
return this._pathName;
- }
+ },
set pathName(nv) {
nv = nv.toString();
if (this._pathName === nv) {
return nv;
}
- this._pathName = identity(Utils.addFinalSlash(nv));
+ this._pathName = identity(nv);
this.rebuildDestination();
this.invalidate(0);
return nv;
- }
+ },
+ _mask: null,
get mask() {
return this._mask;
- }
+ },
set mask(nv) {
if (this._mask === nv) {
return nv;
@@ -1655,11 +1675,14 @@ var QueueItem = class QueueItem {
this.rebuildDestination();
this.invalidate(7);
return nv;
- }
+ },
+ _destinationName: null,
+ destinationNameOverride: null,
+ _destinationNameFull: null,
get destinationName() {
return this._destinationNameFull;
- }
+ },
set destinationName(nv) {
if (this.destinationNameOverride === nv) {
return this._destinationNameFull;
@@ -1668,25 +1691,28 @@ var QueueItem = class QueueItem {
this.rebuildDestination();
this.invalidate(0);
return this._destinationNameFull;
- }
+ },
+ _destinationFile: null,
get destinationFile() {
if (!this._destinationFile) {
this.rebuildDestination();
}
return this._destinationFile;
- }
+ },
+ _destinationLocalFile: null,
get destinationLocalFile() {
if (!this._destinationLocalFile) {
this.rebuildDestination();
}
return this._destinationLocalFile;
- }
+ },
+ _conflicts: 0,
get conflicts() {
return this._conflicts;
- }
+ },
set conflicts(nv) {
if (this._conflicts === nv) {
return nv;
@@ -1695,8 +1721,8 @@ var QueueItem = class QueueItem {
this.rebuildDestination();
this.invalidate(0);
return nv;
- }
-
+ },
+ _tmpFile: null,
get tmpFile() {
if (!this._tmpFile) {
var dest = Prefs.tempLocation ?
@@ -1710,11 +1736,11 @@ var QueueItem = class QueueItem {
this._tmpFile = dest;
}
return this._tmpFile;
- }
-
+ },
+ _hashCollection: null,
get hashCollection() {
return this._hashCollection;
- }
+ },
set hashCollection(nv) {
if (nv && !(nv instanceof DTA.HashCollection)) {
throw new Exception("Not a hash collection");
@@ -1723,58 +1749,99 @@ var QueueItem = class QueueItem {
this._prettyHash = this._hashCollection ?
_('prettyhash', [this._hashCollection.full.type, this._hashCollection.full.sum]) :
TextCache_NAS;
- }
-
+ },
+ _prettyHash: null,
get prettyHash() {
return this._prettyHash;
- }
+ },
+ is: function(state) {
+ return this.state === state;
+ },
+ isOf: function(states) {
+ return (this.state & states) !== 0;
+ },
+ save: function() {
+ if (this.deleting) {
+ return false;
+ }
+ const state = this.state;
+ if ((Prefs.removeCompleted && state === COMPLETE) ||
+ (Prefs.removeCanceled && state === CANCELED) ||
+ (Prefs.removeAborted && state === PAUSED)) {
+ if (this.dbId) {
+ this.remove();
+ }
+ return false;
+ }
+ if (this.isPrivate) {
+ return false;
+ }
+ if (this.dbId) {
+ QueueStore.saveDownload(this.dbId, JSON.stringify(this));
+ return true;
+ }
+ this.dbId = QueueStore.queueDownload(JSON.stringify(this), this.position);
+ return true;
+ },
+ remove: function() {
+ QueueStore.deleteDownload(this.dbId);
+ delete this.dbId;
+ },
+ position: -1,
+ _contentType: "",
get contentType() {
return this._contentType;
- }
+ },
set contentType(nv) {
if (nv === this._contentType) {
return;
}
this._contentType = nv;
delete this._fileNameAndExtension;
- }
-
- get totalSize() {
- return this._totalSize;
- }
+ },
+ visitors: null,
+ relaxSize: false,
+ _totalSize: 0,
+ get totalSize() { return this._totalSize; },
set totalSize(nv) {
if (nv >= 0 && !isNaN(nv)) {
this._totalSize = Math.floor(nv);
}
this.invalidate(3);
this.prealloc();
- }
+ },
+ partialSize: 0,
+ progress: 0,
+ mustGetInfo: false,
get startDate() {
return this._startDate || (this.startDate = new Date());
- }
+ },
set startDate(nv) {
this._startDate = nv;
- }
+ },
+
+ compression: null,
+
+ resumable: true,
+ started: false,
get canResumeLater() {
return this.resumable && !this.isPrivate;
- }
+ },
+ _activeChunks: 0,
get activeChunks() {
return this._activeChunks;
- }
+ },
set activeChunks(nv) {
nv = Math.max(0, nv);
- if (!nv && this.state === RUNNING) {
- log(LOG_INFO, `active chunks set to zero while running: ${nv} ${this._activeChunks}`);
- }
this._activeChunks = nv;
this.invalidate(6);
return this._activeChunks;
- }
-
+ },
+ _maxChunks: 0,
get maxChunks() {
if (!this.urlManager) {
return Prefs.maxChunks;
@@ -1784,7 +1851,7 @@ var QueueItem = class QueueItem {
this._maxChunks = (limit ? limit.segments : 0) || Prefs.maxChunks;
}
return this._maxChunks;
- }
+ },
set maxChunks(nv) {
this._maxChunks = nv;
if (this._maxChunks < this._activeChunks) {
@@ -1804,20 +1871,21 @@ var QueueItem = class QueueItem {
this.invalidate(6);
log(LOG_DEBUG, "mc set to " + nv);
return this._maxChunks;
- }
+ },
+ timeLastProgress: 0,
+ timeStart: 0,
+ _icon: null,
get iconProp() {
if (!this._icon) {
let icon = FileExts.getAtom(this.destinationName, 'metalink' in this).toString();
this._icon = identity((this.isPrivate ? "iconic private file " : "iconic file ") + icon);
}
return this._icon;
- }
-
+ },
get largeIcon() {
return getLargeIcon(this.destinationName, 'metalink' in this);
- }
-
+ },
get dimensionString() {
if (this.partialSize <= 0) {
return TextCache_UNKNOWN;
@@ -1829,30 +1897,27 @@ var QueueItem = class QueueItem {
return Utils.formatBytes(this.totalSize);
}
return _('transfered', [Utils.formatBytes(this.partialSize), Utils.formatBytes(this.totalSize)]);
- }
-
+ },
+ _status : '',
get status() {
- if (this.dialog.offline && this.isOf(QUEUED | PAUSED)) {
+ if (Dialog.offline && this.isOf(QUEUED | PAUSED)) {
return TextCache_OFFLINE;
}
return this._status + (this.autoRetrying ? ' *' : '');
- }
-
+ },
set status(nv) {
if (nv !== this._status) {
this._status = nv;
this.invalidate();
}
return this._status;
- }
-
+ },
get parts() {
if (this.maxChunks) {
return (this.activeChunks) + '/' + this.maxChunks;
}
return '';
- }
-
+ },
get percent() {
const state = this.state;
if (!this.totalSize && state === RUNNING) {
@@ -1865,132 +1930,17 @@ var QueueItem = class QueueItem {
return "100%";
}
return this.progress + "%";
- }
-
+ },
+ _destinationPath: '',
get destinationPath() {
return this._destinationPath;
- }
-
- get isCritical() {
- return this._criticals !== 0;
- }
-
- _setStateInternal(nv) {
- Object.defineProperty(this, "state", {value: nv, configurable: true, enumerable: true});
- }
-
- setState(nv) {
- if (this.state === nv) {
- return nv;
- }
- if (this.state === RUNNING) {
- // remove ourself from inprogresslist
- this.dialog.wasStopped(this);
- // kill the bucket via it's setter
- this.bucket = null;
- }
- else if (this.state === COMPLETE) {
- --this.dialog.completed;
- }
- else if (this.state === FINISHING) {
- --this.dialog.finishing;
- }
- this.speed = '';
- this._setStateInternal(nv);
- if (this.state === RUNNING) {
- // set up the bucket
- this._bucket = new ByteBucket(this.speedLimit, 1.2, "download");
- }
- else if (this.state === FINISHING) {
- ++this.dialog.finishing;
- if (!this.totalSize) {
- // We are done now, just set indeterminate size downloads to what we actually downloaded
- this.refreshPartialSize();
- this.totalSize = this.partialSize;
- }
- }
- else if (this.state === COMPLETE) {
- ++this.dialog.completed;
- }
- this.dialog.signal(this);
- this.invalidate();
- Tree.refreshTools();
- return nv;
- }
-
- setUserFileName(name) {
- try {
- Tree.beginUpdate();
- this.fileNameFromUser = false;
- this.fileName = name;
- this.fileNameFromUser = true;
- this.save();
- let dummy = this.iconProp; // set up initial icon to avoid display problems
- }
- finally {
- Tree.invalidate();
- Tree.endUpdate();
- }
- }
-
- shortenName() {
- let fn = this.destinationName;
- let ext = Utils.getExtension(fn);
- if (ext) {
- fn = fn.substring(0, fn.length - ext.length - 1);
- }
- let nn = fn.substr(0, Math.min(200, Math.max(fn.length - 25, 10)));
- if (nn === fn) {
- return;
- }
- if (ext) {
- nn += "." + ext;
- }
- this.destinationName = nn;
- }
-
- is(state) {
- return this.state === state;
- }
-
- isOf(states) {
- return (this.state & states) !== 0;
- }
-
- save() {
- if (this.deleting) {
- return false;
- }
- const state = this.state;
- if ((Prefs.removeCompleted && state === COMPLETE) ||
- (Prefs.removeCanceled && state === CANCELED) ||
- (Prefs.removeAborted && state === PAUSED)) {
- if (this.dbId) {
- this.remove();
- }
- return false;
- }
- if (this.isPrivate) {
- return false;
- }
- if (this.dbId) {
- QueueStore.saveDownload(this.dbId, JSON.stringify(this));
- return true;
- }
- this.dbId = QueueStore.queueDownload(JSON.stringify(this), this.position);
- return true;
- }
-
- remove() {
- QueueStore.deleteDownload(this.dbId);
- delete this.dbId;
- }
+ },
- invalidate(cell) {
+ invalidate: function(cell) {
Tree.invalidate(this, cell);
- }
+ },
- safeRetry(resumable) {
+ safeRetry: function(resumable) {
this.cancel().then(() => {
// reset flags
this.progress = this.totalSize = this.partialSize = 0;
@@ -2005,11 +1955,11 @@ var QueueItem = class QueueItem {
this.visitors = new VisitorManager();
this.resumable = resumable !== false;
this.setState(QUEUED);
- this.dialog.run(this);
+ Dialog.run(this);
});
- }
+ },
- refreshPartialSize() {
+ refreshPartialSize: function(){
let size = 0;
for (let i = 0, e = this.chunks.length; i < e; ++i) {
size += this.chunks[i].written;
@@ -2029,40 +1979,39 @@ var QueueItem = class QueueItem {
this.progress = 100;
}
}
- }
+ },
- pause() {
+ pause: function(){
this.setState(PAUSED);
if (this.chunks) {
for (let c of this.chunks) {
if (c.running) {
- c.cancelChunk();
+ c.pauseChunk();
}
}
}
this.activeChunks = 0;
this.speeds.clear();
this.otherBytes = 0;
- }
-
- async moveCompleted() {
+ },
+ moveCompleted: function*() {
if (this.state === CANCELED) {
throw Error("Cannot move incomplete file");
}
this.status = TextCache_MOVING;
- let pinned = (await this.resolveConflicts());
+ let pinned = (yield this.resolveConflicts());
if (!pinned) {
return;
}
try {
let destination = new Instances.LocalFile(this.destinationPath);
- await Utils.makeDir(destination, Prefs.dirPermissions);
+ yield Utils.makeDir(destination, Prefs.dirPermissions);
log(LOG_INFO, this.fileName + ": Move " + this.tmpFile.path + " to " + this.destinationFile);
// move file
if (this.compression) {
this.status = TextCache_DECOMPRESSING;
- await new Promise(function(resolve, reject) {
+ yield new Promise(function(resolve, reject) {
new Decompressor(this, function(ex) {
if (ex) {
reject(ex);
@@ -2074,132 +2023,136 @@ var QueueItem = class QueueItem {
}.bind(this));
return true;
}
- await _moveFile(destination, this);
+ yield _moveFile(destination, this);
return true;
}
finally {
ConflictManager.unpin(pinned);
}
return false;
- }
-
- handleMetalink() {
+ },
+ handleMetalink: function() {
try {
Metalinker.handleDownload(this);
}
catch (ex) {
log(LOG_ERROR, "handleMetalink", ex);
}
- }
-
- async verifyHash() {
+ },
+ verifyHash: function() {
let oldStatus = this.status;
this.status = TextCache_VERIFYING;
- let mismatches = await Verificator.verify(
- (await OS.File.exists(this.tmpFile.path)) ? this.tmpFile.path : this.destinationFile,
- this.hashCollection,
- progress => {
- this.partialSize = progress;
- this.invalidate();
- });
- if (!mismatches) {
- log(LOG_ERROR, "hash not computed");
- Prompts.alert(window, _('error', ["Metalink"]), _('verificationfailed', [this.destinationFile]));
- return true;
- }
- else if (mismatches.length) {
- log(LOG_ERROR, "Mismatches: " + mismatches.toSource());
- return (await this.verifyHashError(mismatches));
- }
- this.status = oldStatus;
- return true;
- }
-
- async verifyHashError(mismatches) {
- async function deleteFile(file) {
- try {
- await OS.File.remove(file.path);
+ return Task.spawn((function*() {
+ let mismatches = yield Verificator.verify(
+ (yield OS.File.exists(this.tmpFile.path)) ? this.tmpFile.path : this.destinationFile,
+ this.hashCollection,
+ (function(progress) {
+ this.partialSize = progress;
+ this.invalidate();
+ }).bind(this));
+ if (!mismatches) {
+ log(LOG_ERROR, "hash not computed");
+ Prompts.alert(window, _('error', ["Metalink"]), _('verificationfailed', [this.destinationFile]));
+ return true;
}
- catch (ex if ex.becauseNoSuchFile) {
- // no op
+ else if (mismatches.length) {
+ log(LOG_ERROR, "Mismatches: " + mismatches.toSource());
+ return (yield this.verifyHashError(mismatches));
}
- }
+ this.status = oldStatus;
+ return true;
+ }).bind(this));
+ },
+ verifyHashError: function(mismatches) {
+ let file = this.destinationLocalFile;
- function recoverPartials(download) {
- // merge
- for (let i = mismatches.length - 1; i > 0; --i) {
- if (mismatches[i].start === mismatches[i-1].end + 1) {
- mismatches[i-1].end = mismatches[i].end;
- mismatches.splice(i, 1);
+ return Task.spawn((function*() {
+ function* deleteFile() {
+ try {
+ yield OS.File.remove(file.path);
}
- }
- let chunks = [];
- let next = 0;
- for (let mismatch of mismatches) {
- if (next !== mismatch.start) {
- chunks.push(new Chunk(download, next, mismatch.start - 1, mismatch.start - next));
+ catch (ex) {
+ if (!(ex.becauseNoSuchFile)) {
+ throw ex;
+ } /* else {
+ // no op
+ } */
}
- chunks.push(new Chunk(download, mismatch.start, mismatch.end));
- next = mismatch.end + 1;
- }
- if (next !== download.totalSize) {
- log(LOG_DEBUG, "Inserting last");
- chunks.push(new Chunk(download, next, download.totalSize - 1, download.totalSize - next));
}
- download.chunks = chunks;
- download.refreshPartialSize();
- download.queue();
- }
-
- let file = this.destinationLocalFile;
- filterInSitu(mismatches, e => e.start !== e.end);
- if (mismatches.length && (await OS.File.exists(this.tmpFile.path))) {
- // partials
+ function recoverPartials(download) {
+ // merge
+ for (let i = mismatches.length - 1; i > 0; --i) {
+ if (mismatches[i].start === mismatches[i-1].end + 1) {
+ mismatches[i-1].end = mismatches[i].end;
+ mismatches.splice(i, 1);
+ }
+ }
+ let chunks = [];
+ let next = 0;
+ for (let mismatch of mismatches) {
+ if (next !== mismatch.start) {
+ chunks.push(new Chunk(download, next, mismatch.start - 1, mismatch.start - next));
+ }
+ chunks.push(new Chunk(download, mismatch.start, mismatch.end));
+ next = mismatch.end + 1;
+ }
+ if (next !== download.totalSize) {
+ log(LOG_DEBUG, "Inserting last");
+ chunks.push(new Chunk(download, next, download.totalSize - 1, download.totalSize - next));
+ }
+ download.chunks = chunks;
+ download.refreshPartialSize();
+ download.queue();
+ }
+
+ filterInSitu(mismatches, e => e.start !== e.end);
+
+ if (mismatches.length && (yield OS.File.exists(this.tmpFile.path))) {
+ // partials
+ let act = Prompts.confirm(
+ window,
+ _('verifyerror.title'),
+ _('verifyerror.partialstext'),
+ _('recover'),
+ _('delete'),
+ _('keep'));
+ switch (act) {
+ case 0:
+ yield deleteFile();
+ recoverPartials(this, mismatches);
+ return false;
+ case 1:
+ yield deleteFile();
+ this.cancel();
+ return false;
+ }
+ return true;
+ }
let act = Prompts.confirm(
window,
_('verifyerror.title'),
- _('verifyerror.partialstext'),
- _('recover'),
+ _('verifyerror.text'),
+ _('retry'),
_('delete'),
_('keep'));
switch (act) {
case 0:
- await deleteFile(file);
- recoverPartials(this, mismatches);
+ yield deleteFile();
+ this.safeRetry();
return false;
case 1:
- await deleteFile(file);
+ yield deleteFile();
this.cancel();
return false;
}
return true;
- }
- let act = Prompts.confirm(
- window,
- _('verifyerror.title'),
- _('verifyerror.text'),
- _('retry'),
- _('delete'),
- _('keep'));
- switch (act) {
- case 0:
- await deleteFile();
- this.safeRetry();
- return false;
- case 1:
- await deleteFile();
- this.cancel();
- return false;
- }
- return true;
- }
-
- customFinishEvent() {
+ }).bind(this));
+ },
+ customFinishEvent: function() {
new CustomAction(this, Prefs.finishEvent);
- }
-
- async setAttributes() {
+ },
+ setAttributes: function*() {
if (Prefs.setTime) {
// XXX: async API
try {
@@ -2229,107 +2182,107 @@ var QueueItem = class QueueItem {
file = this.destinationLocalFile;
}
try {
- this.totalSize = this.partialSize = (await OS.File.stat(file.path)).size;
+ this.totalSize = this.partialSize = (yield OS.File.stat(file.path)).size;
}
catch (ex) {
log(LOG_ERROR, "failed to get filesize for " + file.path, ex);
this.totalSize = this.partialSize = 0;
}
return true;
- }
-
- async closeChunks() {
+ },
+ closeChunks: function*() {
if (!this.chunks) {
return;
}
- for (let i = 0; i < this.chunks.length; ++i) {
- let c = this.chunks[i];
- await c.close();
- this.chunks[i] = c.clone();
+ for (let c of this.chunks) {
+ yield c.close();
}
- }
-
- critical() {
+ },
+ _criticals: 0,
+ get isCritical() {
+ return this._criticals !== 0;
+ },
+ critical: function() {
this._criticals++;
- }
-
- uncritical() {
+ },
+ uncritical: function() {
this._criticals = Math.max(0, this._criticals - 1);
- }
-
- finishDownload(exception) {
+ },
+ finishDownload: function(exception) {
if (this._finishDownloadTask) {
- return this._finishDownloadTask;
+ return;
}
log(LOG_DEBUG, "finishDownload, connections: " + this.sessionConnections);
// Last speed update
this.refreshPartialSize();
- this.dialog._sum += this.speeds.add(this.partialSize + this.otherBytes, Utils.getTimestamp());
+ Dialog._sum += this.speeds.add(this.partialSize + this.otherBytes, Utils.getTimestamp());
if (!this.partialSize) {
log(LOG_ERROR, "INVALID SIZE!!!!!");
this.fail(_("accesserror"), _("accesserror.long"), _("accesserror"));
return;
}
- return this._finishDownloadTask = this._runFinishDownloadTask();
- }
-
- async _runFinishDownloadTask() {
- try {
- this.setState(FINISHING);
- this.status = TextCache_FINISHING;
- await this.closeChunks();
- if (this.hashCollection && !(await this.verifyHash())) {
- return;
- }
- if ("isMetalink" in this) {
- this.handleMetalink();
- return;
- }
+ this._finishDownloadTask = Task.spawn(function* finishDownloadTask() {
try {
- if (!(await this.moveCompleted())) {
- log(LOG_DEBUG, "moveCompleted scheduled!");
+ this.setState(FINISHING);
+ yield this.closeChunks();
+ if (this.hashCollection && !(yield this.verifyHash())) {
return;
}
- }
- catch (iex) {
- log(LOG_ERROR, "move failed", iex);
- this.fail(
- _("moveerror"),
- _("moveerror.long"),
- _("moveerror.status", iex.message || iex)
- );
- return;
- }
-
- await this.setAttributes();
- if (Prefs.finishEvent) {
- this.customFinishEvent();
- }
- this.chunks.length = 0;
- this.speeds.clear();
- this.activeChunks = 0;
- this.setState(COMPLETE);
- this.status = TextCache_COMPLETE;
- this.visitors = new VisitorManager();
- this.compression = null;
- }
- catch (ex) {
- log(LOG_ERROR, "complete: ", ex);
- this.fail(_("accesserror"), _("accesserror.long"), _("accesserror"));
- }
- finally {
- delete this._finishDownloadTask;
- }
- }
-
- rebuildDestination() {
+ if ("isMetalink" in this) {
+ this.handleMetalink();
+ return;
+ }
+ if (!(yield this.moveCompleted())) {
+ log(LOG_DEBUG, "moveCompleted scheduled!");
+ return;
+ }
+ yield this.setAttributes();
+ if (Prefs.finishEvent) {
+ this.customFinishEvent();
+ }
+ this.chunks.length = 0;
+ this.speeds.clear();
+ this.activeChunks = 0;
+ this.setState(COMPLETE);
+ this.status = TextCache_COMPLETE;
+ this.visitors = new VisitorManager();
+ this.compression = null;
+ }
+ catch (ex) {
+ log(LOG_ERROR, "complete: ", ex);
+ this.fail(_("accesserror"), _("accesserror.long"), _("accesserror"));
+ }
+ finally {
+ delete this._finishDownloadTask;
+ }
+ }.bind(this));
+ },
+ get maskURL() {
+ return this.urlManager.usableURL;
+ },
+ get maskCURL() {
+ return Utils.getCURL(this.maskURL);
+ },
+ get maskURLPath() {
+ return this.urlManager.usableURLPath;
+ },
+ get maskReferrerURL() {
+ return this.referrerUrlManager.usableURL;
+ },
+ get maskReferrerURLPath() {
+ return this.referrerUrlManager.usableURLPath;
+ },
+ get maskReferrerCURL() {
+ return Utils.getCURL(this.maskReferrerURL);
+ },
+ rebuildDestination: function() {
try {
let mask = Utils.removeFinalSlash(Utils.normalizeSlashes(Utils.removeFinalChar(
this.rebuildDestination_renamer(this.mask), "."
)));
- let file = new Instances.LocalFile(this.pathName);
+ let file = new Instances.LocalFile(Utils.addFinalSlash(this.pathName));
if (!~mask.indexOf(Utils.SYSTEMSLASH)) {
file.append(Utils.removeBadChars(mask).trim());
}
@@ -2365,21 +2318,17 @@ var QueueItem = class QueueItem {
}
finally {
this._icon = null;
- let dummy = this.iconProp; // set up initial icon to avoid display problems
+ this.iconProp; // set up initial icon to avoid display problems
FileExts.add();
}
- }
-
- checkConflicts() {
+ },
+ checkConflicts: function() {
return ConflictManager.check(this);
- }
-
- resolveConflicts() {
+ },
+ resolveConflicts: function() {
return ConflictManager.resolve(this);
-
- }
-
- fail(title, msg, state) {
+ },
+ fail: function(title, msg, state) {
log(LOG_INFO, "failDownload invoked");
this.cancel(state);
@@ -2396,9 +2345,9 @@ var QueueItem = class QueueItem {
window.alert(msg);
break;
}
- }
+ },
- cancel(message) {
+ cancel: function(message) {
try {
const state = this.state;
if (state === RUNNING) {
@@ -2414,66 +2363,65 @@ var QueueItem = class QueueItem {
this.activeChunks = 0;
}
this.setState(CANCELED);
- return this._cancelClose(message);
- }
- catch(ex) {
- log(LOG_ERROR, "cancel():", ex);
- }
- }
-
- async _cancelClose(message) {
- try {
- await this.closeChunks();
- if (this._preallocTask) {
- await this._preallocTask;
- }
- log(LOG_INFO, this.fileName + ": canceled");
+ return Task.spawn(function*() {
+ try {
+ yield this.closeChunks();
+ if (this._preallocTask) {
+ yield this._preallocTask;
+ }
+ log(LOG_INFO, this.fileName + ": canceled");
- this.shutdown();
- await this.removeTmpFile();
+ this.shutdown();
+ this.removeTmpFile();
- // gc
- if (this.deleting) {
- return;
- }
- if (!message) {
- message = _("canceled");
- }
+ // gc
+ if (this.deleting) {
+ return;
+ }
+ if (!message) {
+ message = _("canceled");
+ }
- this.status = message;
- this.visitors = new VisitorManager();
- this.chunks.length = 0;
- this.progress = this.totalSize = this.partialSize = 0;
- this.conflicts = 0;
- this.resumable = true;
- this._maxChunks = this._activeChunks = 0;
- this._autoRetries = 0;
- delete this._autoRetryTime;
- this.speeds.clear();
- this.otherBytes = 0;
- this.save();
+ this.status = message;
+ this.visitors = new VisitorManager();
+ this.chunks.length = 0;
+ this.progress = this.totalSize = this.partialSize = 0;
+ this.conflicts = 0;
+ this.resumable = true;
+ this._maxChunks = this._activeChunks = 0;
+ this._autoRetries = 0;
+ delete this._autoRetryTime;
+ this.speeds.clear();
+ this.otherBytes = 0;
+ this.save();
+ }
+ catch (ex) {
+ log(LOG_ERROR, "cancel() Task", ex);
+ }
+ }.bind(this));
}
- catch (ex) {
- log(LOG_ERROR, "cancel() Task", ex);
+ catch(ex) {
+ log(LOG_ERROR, "cancel():", ex);
}
- }
-
- async cleanup() {
- if (this.chunks) {
- await this.closeChunks();
- }
- delete this.visitors;
- delete this.chunks;
- delete this.speeds;
- delete this.urlManager;
- delete this.referrer;
- delete this._referrerUrlManager;
- delete this._destinationLocalFile;
- delete this._tmpFile;
- delete this.rebuildDestination_renamer;
- }
+ },
- prealloc() {
+ cleanup: function() {
+ Task.spawn(function*() {
+ if (this.chunks) {
+ yield this.closeChunks();
+ }
+ delete this.visitors;
+ delete this.chunks;
+ delete this.speeds;
+ delete this.urlManager;
+ delete this.referrer;
+ delete this._referrerUrlManager;
+ delete this._destinationLocalFile;
+ delete this._tmpFile;
+ delete this.rebuildDestination_renamer;
+ }.bind(this));
+ },
+ prealloc: function() {
let file = this.tmpFile;
if (this.state !== RUNNING) {
@@ -2489,82 +2437,98 @@ var QueueItem = class QueueItem {
return;
}
- this._preallocTask = this._preallocInternal(file);
- }
-
- async _preallocInternal(file) {
- try {
- try {
- await Utils.makeDir(file.parent, Prefs.dirPermissions);
- }
- catch (ex if ex.becauseExists) {
- // no op
- }
+ this._preallocTask = Task.spawn(function*() {
try {
- if (this.totalSize === (await OS.File.stat(file.path)).size) {
- log(LOG_INFO, "pa: already allocated");
- return;
+ try {
+ yield Utils.makeDir(file.parent, Prefs.dirPermissions);
+ }
+ catch (ex) {
+ if (!(ex.becauseExists)) {
+ throw ex;
+ } /* else {
+ // no op
+ } */
+ }
+ try {
+ if (this.totalSize === (yield OS.File.stat(file.path)).size) {
+ log(LOG_INFO, "pa: already allocated");
+ return;
+ }
+ }
+ catch (ex) {
+ if (!(ex.becauseNoSuchFile)) {
+ throw ex;
+ } /* else {
+ // no op
+ } */
+ }
+ let pa = Preallocator.prealloc(
+ file,
+ this.totalSize,
+ Prefs.permissions,
+ Prefs.sparseFiles
+ );
+ if (pa) {
+ yield pa;
+ log(LOG_INFO, "pa: done");
+ }
+ else {
+ log(LOG_INFO, "pa: not preallocating");
}
}
- catch (ex if ex.becauseNoSuchFile) {
- // no op
- }
- let pa = Preallocator.prealloc(
- file,
- this.totalSize,
- Prefs.permissions,
- Prefs.sparseFiles
- );
- if (pa) {
- await pa;
- log(LOG_INFO, "pa: done");
+ catch(ex) {
+ log(LOG_ERROR, "pa: failed", ex);
}
- else {
- log(LOG_INFO, "pa: not preallocating");
+ finally {
+ this._preallocTask = null;
+ this.maybeResumeDownload();
}
- }
- catch(ex) {
- log(LOG_ERROR, "pa: failed", ex);
- }
- finally {
- this._preallocTask = null;
- this.maybeResumeDownload();
- }
- }
+ }.bind(this));
+ },
- shutdown() { }
+ shutdown: function() {
+ },
- async removeTmpFile() {
+ removeTmpFile: function() {
let tmpFile = this._tmpFile;
delete this._tmpFile;
if (!tmpFile) {
return;
}
- try {
- await OS.File.remove(tmpFile.path);
- }
- catch (ex if ex.becauseNoSuchFile) {
- // no op
- }
- catch (ex) {
+ Task.spawn(function*() {
+ try {
+ yield OS.File.remove(tmpFile.path);
+ } catch (ex) {
+ if (!(ex.becauseNoSuchFile)) {
+ throw ex;
+ } /* else {
+ // no op
+ } */
+ }
+ }).then(null, function(ex) {
log(LOG_ERROR, "failed to remove tmpfile: " + tmpFile.path, ex);
- }
- }
+ });
+ },
- pauseAndRetry() {
+ sessionConnections: 0,
+ _autoRetries: 0,
+ _autoRetryTime: 0,
+ get autoRetrying() {
+ return !!this._autoRetryTime;
+ },
+ pauseAndRetry: function() {
let retry = this.state === RUNNING;
this.pause();
this.resumable = true;
if (retry && Prefs.autoRetryInterval && !(Prefs.maxAutoRetries && Prefs.maxAutoRetries <= this._autoRetries)) {
- this.dialog.markAutoRetry(this);
+ Dialog.markAutoRetry(this);
this._autoRetryTime = Utils.getTimestamp();
log(LOG_INFO, "marked auto-retry: " + this);
}
this.save();
- }
-
- autoRetry() {
+ },
+ autoRetry: function() {
if (!this.autoRetrying || Utils.getTimestamp() - (Prefs.autoRetryInterval * 1000) < this._autoRetryTime) {
return false;
}
@@ -2574,40 +2538,55 @@ var QueueItem = class QueueItem {
this.queue();
log(LOG_DEBUG, "Requeued due to auto-retry: " + this);
return true;
- }
- clearAutoRetry() {
+ },
+ clearAutoRetry: function() {
this._autoRetryTime = 0;
this._autoRetries = 0;
- }
-
- queue() {
+ },
+ queue: function() {
this._autoRetryTime = 0;
this.setState(QUEUED);
this.status = TextCache_QUEUED;
- }
-
- maybeResumeDownload() {
+ },
+ maybeResumeDownload: function() {
if (this.state !== RUNNING) {
return;
}
this.resumeDownload();
- }
-
- resumeDownload() {
+ },
+ resumeDownload: function() {
log(LOG_DEBUG, "resumeDownload: " + this);
-
- // merge finished chunks together, so that the scoreboard does not bloat
- // that much
- for (let i = this.chunks.length - 2; i > -1; --i) {
- let c1 = this.chunks[i], c2 = this.chunks[i + 1];
- if (c1.complete && c2.complete && !c1.buffered && !c2.buffered) {
- c1.merge(c2);
- this.chunks.splice(i + 1, 1);
+ function cleanChunks(d) {
+ // merge finished chunks together, so that the scoreboard does not bloat
+ // that much
+ for (let i = d.chunks.length - 2; i > -1; --i) {
+ let c1 = d.chunks[i], c2 = d.chunks[i + 1];
+ if (c1.complete && c2.complete && !c1.buffered && !c2.buffered) {
+ c1.merge(c2);
+ d.chunks.splice(i + 1, 1);
+ }
}
}
+ function downloadNewChunk(download, start, end, header) {
+ let chunk = new Chunk(download, start, end);
+ download.chunks.push(chunk);
+ download.chunks.sort(function(a,b) { return a.start - b.start; });
+ downloadChunk(download, chunk, header);
+ }
+ function downloadChunk(download, chunk, header) {
+ chunk.download = new Connection(download, chunk, header || download.mustGetInfo);
+ chunk.running = true;
+ download.mustGetInfo = false;
+ download.setState(RUNNING);
+ log(LOG_DEBUG, "started: " + chunk);
+ ++download.activeChunks;
+ ++download.sessionConnections;
+ }
+
+ cleanChunks(this);
try {
- if (this.dialog.offline || this.maxChunks <= this.activeChunks) {
+ if (Dialog.offline || this.maxChunks <= this.activeChunks) {
return false;
}
@@ -2634,7 +2613,7 @@ var QueueItem = class QueueItem {
// restart paused chunks
if (paused.length) {
let p = paused.shift();
- downloadOldChunk(this, p, p.end === 0);
+ downloadChunk(this, p, p.end === 0);
rv = true;
continue;
}
@@ -2670,21 +2649,15 @@ var QueueItem = class QueueItem {
downloadNewChunk(this, biggest.end + 1, end);
rv = true;
}
- if (this.activeChunks < 1 &&
- this.chunks.some(chunk => !(chunk.running || chunk.complete))) {
- throw new Error("Nothing started but no actives, yet paused");
- }
return rv;
}
catch(ex) {
- this.dumpScoreboard();
- log(LOG_ERROR, "resumeDownload():", ex, true);
+ log(LOG_ERROR, "resumeDownload():", ex);
}
return false;
- }
-
- replaceMirrors(mirrors) {
+ },
+ replaceMirrors: function(mirrors) {
let restart = this.urlManager.length < 3;
this.urlManager.initByArray(mirrors);
if (restart && this.resumable && this.state === RUNNING && this.maxChunks > 2) {
@@ -2696,9 +2669,8 @@ var QueueItem = class QueueItem {
}
this.invalidate();
this.save();
- }
-
- dumpScoreboard() {
+ },
+ dumpScoreboard: function() {
if (!log.enabled) {
return;
}
@@ -2708,13 +2680,11 @@ var QueueItem = class QueueItem {
scoreboard += i + ": " + c + "\n";
}
log(LOG_DEBUG, "scoreboard\n" + scoreboard);
- }
-
- toString() {
+ },
+ toString: function() {
return this.urlManager.usable;
- }
-
- toJSON() {
+ },
+ toJSON: function() {
let rv = Object.create(null);
let p = Object.getPrototypeOf(this);
for (let u of Dialog_serialize_props) {
@@ -2764,64 +2734,205 @@ var QueueItem = class QueueItem {
return rv;
}
};
-Object.assign(QueueItem.prototype, {
- state: QUEUED,
- position: -1,
- _contentType: "",
- _description: null,
- _hashCollection: null,
- _mask: null,
- _pathName: null,
- _prettyHash: null,
- _status : '',
- _title: '',
- bNum: 0,
- compression: null,
- fromMetalink: false,
- iNum: 0,
- postData: null,
- visitors: null,
+XPCOMUtils.defineLazyGetter(QueueItem.prototype, 'AuthPrompts', function() {
+ const {LoggedPrompter} = require("support/loggedprompter");
+ return new LoggedPrompter(window);
+});
- _destinationFile: null,
- _destinationLocalFile: null,
- _destinationName: null,
- _destinationNameFull: null,
- _destinationPath: '',
- _fileName: null,
- _tmpFile: null,
- destinationNameOverride: null,
- fileNameFromUser: false,
+var ConflictManager = {
+ _items: new Map(),
+ _queue: [],
+ _pinned: new Map(),
+ resolve: function(download) {
+ return this._resolve(download, true);
+ },
+ check: function(download) {
+ return this._resolve(download, false);
+ },
+ _resolve: function(download, pinned) {
+ log(LOG_DEBUG, "ConflictManager: Resolving " + download);
+ let data = this._items.get(download);
+ if (data) {
+ // Make sure pinning request is carried over
+ data.pinned |= pinned;
+ log(LOG_DEBUG, "ConflictManager: Resolving already " + data);
+ return data.promise;
+ }
+ data = {pinned: pinned};
+ data.promise = new Promise(function(resolve, reject) {
+ data.reject = reject;
+ data.resolve = resolve;
+ });
+ this._items.set(download,data);
+ this._queue.push(download);
+ log(LOG_DEBUG, "ConflictManager: Resolving new " + data);
+ this._processNext();
+ return data.promise;
+ },
+ pin: function(name, unique) {
+ let count = (this._pinned.get(name) || 0) + 1;
+ if (unique && count > 1) {
+ throw new Error("Invalid pin; not unique");
+ }
+ this._pinned.set(name, count);
+ },
+ unpin: function(name) {
+ let count = this._pinned.get(name);
+ if (!isFinite(count)) {
+ log(LOG_ERROR, "ConflictManager: trying to unpin a name that does not exist");
+ this._pinned.delete(name);
+ return;
+ }
+ if (--count <= 0) {
+ this._pinned.delete(name);
+ return;
+ }
+ this._pinned.set(name, count); // store new count
+ },
+ _processNext: function() {
+ log(LOG_DEBUG, "ConflictManager: Resolving next");
+ if (this._processing) {
+ log(LOG_DEBUG, "ConflictManager: Resolving rescheduling");
+ return;
+ }
+ let download = this._queue.shift();
+ if (!download) {
+ return;
+ }
+ let data = this._items.get(download);
+ this._items.delete(download);
- _totalSize: 0,
- otherBytes: 0,
- partialSize: 0,
- progress: 0,
- relaxSize: false,
+ this._processing = true;
+ Task.spawn(function*() {
+ try {
+ data.resolve(yield this._processOne(download, data));
+ }
+ catch (ex) {
+ log(LOG_ERROR, "ConflictManager: Failed to resolve", ex);
+ data.reject(null);
+ }
+ finally {
+ this._processing = false;
+ setTimeoutOnlyFun(this._processNext.bind(this), 0);
+ }
+ }.bind(this));
+ },
+ _findUnique: function*(newDest, basename, conflicts) {
+ for (;; ++conflicts) {
+ newDest.leafName = Utils.formatConflictName(basename, conflicts);
+ let exists = this._pinned.has(newDest.path);
+ if (!exists) {
+ exists = yield OS.File.exists(newDest.path);
+ // recheck
+ exists = exists || this._pinned.has(newDest.path);
+ }
+ if (!exists) {
+ return conflicts;
+ }
+ }
+ },
+ _processOne: function*(download, data) {
+ log(LOG_DEBUG, "ConflictManager: Starting conflict resolution for " + download);
+ let dest = download.destinationLocalFile;
+ let exists = this._pinned.has(dest.path);
+ if (!exists) {
+ exists = yield OS.File.exists(dest.path);
+ // recheck
+ exists = exists || this._pinned.has(dest.path);
+ }
+ if (!exists) {
+ log(LOG_DEBUG, "ConflictManager: Does not exist " + download);
+ if (data.pinned) {
+ this.pin(dest.path, true);
+ }
+ return dest.path;
+ }
- _activeChunks: 0,
- _maxChunks: 0,
- timeLastProgress: 0,
- timeStart: 0,
+ let cr = -1;
- _bucket: null,
- _icon: null,
+ let conflicts = 0;
+ const basename = download.destinationName;
+ let newDest = download.destinationLocalFile.clone();
- _autoRetries: 0,
- _autoRetryTime: 0,
- _conflicts: 0,
- _criticals: 0,
- _speedLimit: -1,
- mustGetInfo: false,
- resumable: true,
- sessionConnections: 0,
- started: false,
-});
+ if (Prefs.conflictResolution !== 3) {
+ cr = Prefs.conflictResolution;
+ }
+ else if (download.shouldOverwrite) {
+ cr = 1;
+ }
+ else if ('_sessionSetting' in this) {
+ cr = this._sessionSetting;
+ }
+ else if ('_conflictSetting' in download) {
+ cr = download._conflictSetting;
+ }
-XPCOMUtils.defineLazyGetter(QueueItem.prototype, 'AuthPrompts', function() {
- const {LoggedPrompter} = require("support/loggedprompter");
- return new LoggedPrompter(window);
-});
+ if (cr < 0) {
+ let dialog = {};
+ dialog.promise = new Promise(function(resolve, reject) {
+ dialog.resolve = resolve;
+ dialog.reject = reject;
+ });
+ conflicts = yield this._findUnique(newDest, basename, conflicts);
+ let options = {
+ url: Utils.cropCenter(download.urlManager.usable, 45),
+ fn: Utils.cropCenter(download.destinationLocalFile.leafName, 45),
+ newDest: Utils.cropCenter(newDest.leafName, 45)
+ };
+ window.openDialog(
+ "chrome://dta/content/dta/manager/conflicts.xul",
+ "_blank",
+ "chrome,centerscreen,resizable=no,dialog,close=no,dependent",
+ options, dialog
+ );
+ let ctype = 0;
+ [cr, ctype] = yield dialog.promise;
+
+ if (ctype === 1) {
+ this._sessionSetting = cr;
+ }
+ else if (ctype === 2) {
+ Preferences.setExt('conflictresolution', cr);
+ }
+ else {
+ download._conflictSetting = cr;
+ }
+ }
+
+ switch (cr) {
+ case 0: {
+ if (!data.pinned) {
+ // No need to actually check here...
+ // Check will be performed once we pin
+ return;
+ }
+ conflicts = yield this._findUnique(newDest, basename, conflicts);
+ let pinned = null;
+ if (data.pinned) {
+ download.conflicts = conflicts;
+ pinned = download.destinationFile;
+ download.shouldOverwrite = false;
+ this.pin(pinned, true);
+ }
+ log(LOG_DEBUG, "ConflictManager: resolved setting conflicts for " + download);
+ return pinned;
+ }
+ case 1: {
+ let pinned = null;
+ if (data.pinned) {
+ pinned = download.destinationFile;
+ download.shouldOverwrite = true;
+ this.pin(pinned, false);
+ }
+ return pinned;
+ }
+ default:
+ download.cancel(_('skipped'));
+ return false;
+ }
+ }
+};
function CustomAction(download, command) {
try {
@@ -2887,7 +2998,7 @@ var startDownloads = (function() {
let addItem = function(e) {
try {
- let qi = new QueueItem(Dialog);
+ let qi = new QueueItem();
let lnk = e.url;
if (typeof lnk === 'string') {
qi.urlManager = new UrlManager([new DTA.URL(Services.io.newURI(lnk, null, null))]);
diff --git a/chrome/content/dta/manager/manager.xul b/chrome/content/dta/manager/manager.xul
index d0fe2bdaf..5a636c58e 100644
--- a/chrome/content/dta/manager/manager.xul
+++ b/chrome/content/dta/manager/manager.xul
@@ -54,9 +54,9 @@
-
-
-
+
+
+
@@ -293,7 +293,7 @@