commit f1aa68f82b138d193c86a18b68cfc78f6ba14632
parent b298e7acbd8a8d92986c5bcd42c236e829f496eb
Author: Dan Stillman <dstillman@zotero.org>
Date: Wed, 21 Mar 2012 19:39:40 -0400
Simplify the file sync code a bit
Just call Zotero.Sync.Storage.[ZFS/WebDAV] directly
This probably breaks some things.
Diffstat:
12 files changed, 1515 insertions(+), 1539 deletions(-)
diff --git a/chrome/content/zotero/preferences/preferences.js b/chrome/content/zotero/preferences/preferences.js
@@ -291,7 +291,7 @@ function updateStorageSettings(enabled, protocol, skipWarnings) {
var sql = "INSERT OR IGNORE INTO settings VALUES (?,?,?)";
Zotero.DB.query(sql, ['storage', 'zfsPurge', 'user']);
- Zotero.Sync.Storage.purgeDeletedStorageFiles('zfs', function (success) {
+ Zotero.Sync.Storage.ZFS.purgeDeletedStorageFiles(function (success) {
if (success) {
ps.alert(
null,
@@ -363,7 +363,7 @@ function verifyStorageServer() {
abortButton.hidden = false;
progressMeter.hidden = false;
- var requestHolder = Zotero.Sync.Storage.checkServer('WebDAV', function (uri, status, callback) {
+ var requestHolder = Zotero.Sync.Storage.WebDAV.checkServer(function (uri, status, callback) {
verifyButton.hidden = false;
abortButton.hidden = true;
progressMeter.hidden = true;
@@ -388,7 +388,7 @@ function verifyStorageServer() {
break;
}
- callback(uri, status, window);
+ Zotero.Sync.Storage.WebDAV.checkServerCallback(uri, status, window);
});
abortButton.onclick = function () {
diff --git a/chrome/content/zotero/preferences/preferences.xul b/chrome/content/zotero/preferences/preferences.xul
@@ -157,7 +157,7 @@ To add a new preference:
<prefpane id="zotero-prefpane-sync"
label="&zotero.preferences.prefpane.sync;"
- onpaneload="document.getElementById('sync-password').value = Zotero.Sync.Server.password; document.getElementById('storage-password').value = Zotero.Sync.Storage.password;"
+ onpaneload="document.getElementById('sync-password').value = Zotero.Sync.Server.password; var pass = Zotero.Sync.Storage.WebDAV.password; if (pass) { document.getElementById('storage-password').value = pass; }"
image="chrome://zotero/skin/prefs-sync.png"
helpTopic="sync">
<preferences>
@@ -283,7 +283,7 @@ To add a new preference:
preference="pref-storage-username"
onkeypress="if (Zotero.isMac && event.keyCode == 13) { this.blur(); setTimeout(verifyStorageServer, 1); }"
onsynctopreference="unverifyStorageServer();"
- onchange="var pass = document.getElementById('storage-password'); if (pass.value) { Zotero.Sync.Storage.Session.WebDAV.prototype.password = pass.value; }"/>
+ onchange="var pass = document.getElementById('storage-password'); if (pass.value) { Zotero.Sync.Storage.WebDAV.password = pass.value; }"/>
</hbox>
</row>
<row>
@@ -292,7 +292,7 @@ To add a new preference:
<textbox id="storage-password" flex="0" type="password"
onkeypress="if (Zotero.isMac && event.keyCode == 13) { this.blur(); setTimeout(verifyStorageServer, 1); }"
oninput="unverifyStorageServer()"
- onchange="Zotero.Sync.Storage.Session.WebDAV.prototype.password = this.value"/>
+ onchange="Zotero.Sync.Storage.WebDAV.password = this.value;"/>
</hbox>
</row>
<row>
diff --git a/chrome/content/zotero/xpcom/data/relations.js b/chrome/content/zotero/xpcom/data/relations.js
@@ -252,9 +252,13 @@ Zotero.Relations = new function () {
}
relation.libraryID = parseInt(libraryID);
}
- relation.subject = _getFirstChildContent(relationNode, 'subject');
- relation.predicate = _getFirstChildContent(relationNode, 'predicate');
- relation.object = _getFirstChildContent(relationNode, 'object');
+
+ var elems = Zotero.Utilities.xpath(relationNode, 'subject');
+ relation.subject = elems.length ? elems[0].textContent : "";
+ var elems = Zotero.Utilities.xpath(relationNode, 'predicate');
+ relation.predicate = elems.length ? elems[0].textContent : "";
+ var elems = Zotero.Utilities.xpath(relationNode, 'object');
+ relation.object = elems.length ? elems[0].textContent : "";
return relation;
}
diff --git a/chrome/content/zotero/xpcom/storage.js b/chrome/content/zotero/xpcom/storage.js
@@ -87,41 +87,41 @@ Zotero.Sync.Storage = new function () {
//
// Public methods
//
- this.sync = function (moduleName, observer) {
- var module = getModuleFromName(moduleName);
+ this.sync = function (modeName, observer) {
+ var mode = getModeFromName(modeName);
if (!observer) {
throw new Error("Observer not provided");
}
- registerDefaultObserver(moduleName);
- Zotero.Sync.Storage.EventManager.registerObserver(observer, true, moduleName);
+ registerDefaultObserver(modeName);
+ Zotero.Sync.Storage.EventManager.registerObserver(observer, true, modeName);
- if (!module.active) {
- if (!module.enabled) {
- Zotero.debug(module.name + " file sync is not enabled");
+ if (!mode.active) {
+ if (!mode.enabled) {
+ Zotero.debug(mode.name + " file sync is not enabled");
Zotero.Sync.Storage.EventManager.skip();
return;
}
- Zotero.debug(module.name + " file sync is not active");
+ Zotero.debug(mode.name + " file sync is not active");
// Try to verify server now if it hasn't been
- if (!module.verified) {
- module.checkServer(function (uri, status) {
+ if (!mode.verified) {
+ mode.checkServer(function (uri, status) {
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var lastWin = wm.getMostRecentWindow("navigator:browser");
- var success = module.checkServerCallback(uri, status, lastWin, true);
+ var success = mode.checkServerCallback(uri, status, lastWin, true);
if (success) {
- Zotero.debug(module.name + " file sync is successfully set up");
- Zotero.Sync.Storage.sync(module.name);
+ Zotero.debug(mode.name + " file sync is successfully set up");
+ Zotero.Sync.Storage.sync(mode.name);
}
else {
- Zotero.debug(module.name + " verification failed");
+ Zotero.debug(mode.name + " verification failed");
var e = new Zotero.Error(
- Zotero.getString('sync.storage.error.verificationFailed', module.name),
+ Zotero.getString('sync.storage.error.verificationFailed', mode.name),
0,
{
dialogButtonText: Zotero.getString('sync.openSyncPreferences'),
@@ -141,8 +141,8 @@ Zotero.Sync.Storage = new function () {
return;
}
- if (!module.includeUserFiles && !module.includeGroupFiles) {
- Zotero.debug("No libraries are enabled for " + module.name + " syncing");
+ if (!mode.includeUserFiles && !mode.includeGroupFiles) {
+ Zotero.debug("No libraries are enabled for " + mode.name + " syncing");
Zotero.Sync.Storage.EventManager.skip();
return;
}
@@ -153,7 +153,7 @@ Zotero.Sync.Storage = new function () {
);
}
- Zotero.debug("Beginning " + module.name + " file sync");
+ Zotero.debug("Beginning " + mode.name + " file sync");
_syncInProgress = true;
_changesMade = false;
@@ -161,8 +161,8 @@ Zotero.Sync.Storage = new function () {
Zotero.Sync.Storage.checkForUpdatedFiles(
null,
null,
- module.includeUserFiles && Zotero.Sync.Storage.downloadOnSync(),
- module.includeGroupFiles && Zotero.Sync.Storage.downloadOnSync('groups')
+ mode.includeUserFiles && Zotero.Sync.Storage.downloadOnSync(),
+ mode.includeGroupFiles && Zotero.Sync.Storage.downloadOnSync('groups')
);
}
catch (e) {
@@ -171,14 +171,14 @@ Zotero.Sync.Storage = new function () {
var self = this;
- module.getLastSyncTime(function (lastSyncTime) {
+ mode.getLastSyncTime(function (lastSyncTime) {
// Register the observers again to make sure they're active when we
// start the queues. (They'll only be registered once.) Observers are
// cleared when all queues finish, so without this another sync
// process (e.g., on-demand download) could finish and clear all
// observers while getLastSyncTime() is running.
- registerDefaultObserver(moduleName);
- Zotero.Sync.Storage.EventManager.registerObserver(observer, true, moduleName);
+ registerDefaultObserver(modeName);
+ Zotero.Sync.Storage.EventManager.registerObserver(observer, true, modeName);
var download = true;
@@ -186,17 +186,17 @@ Zotero.Sync.Storage = new function () {
var force = !!Zotero.DB.valueQuery(sql, Zotero.Sync.Storage.SYNC_STATE_FORCE_DOWNLOAD);
if (!force && lastSyncTime) {
- var sql = "SELECT version FROM version WHERE schema='storage_" + moduleName + "'";
+ var sql = "SELECT version FROM version WHERE schema='storage_" + modeName + "'";
var version = Zotero.DB.valueQuery(sql);
if (version == lastSyncTime) {
- Zotero.debug("Last " + module.name + " sync time hasn't changed -- skipping file download step");
+ Zotero.debug("Last " + mode.name + " sync time hasn't changed -- skipping file download step");
download = false;
}
}
try {
- var activeDown = download ? _downloadFiles(module) : false;
- var activeUp = _uploadFiles(module);
+ var activeDown = download ? _downloadFiles(mode) : false;
+ var activeUp = _uploadFiles(mode);
}
catch (e) {
Zotero.Sync.Storage.EventManager.error(e);
@@ -620,9 +620,9 @@ Zotero.Sync.Storage = new function () {
*/
this.downloadFile = function (item, requestCallbacks) {
var itemID = item.id;
- var module = getModuleFromLibrary(item.libraryID);
+ var mode = getModeFromLibrary(item.libraryID);
- if (!module || !module.active) {
+ if (!mode || !mode.active) {
Zotero.debug("File syncing is not active for item's library -- skipping download");
return false;
}
@@ -681,7 +681,7 @@ Zotero.Sync.Storage = new function () {
requestCallbacks = {};
}
var onStart = function (request) {
- module.downloadFile(request);
+ mode.downloadFile(request);
};
requestCallbacks.onStart = requestCallbacks.onStart
? [onStart, requestCallbacks.onStart]
@@ -699,7 +699,7 @@ Zotero.Sync.Storage = new function () {
};
setup();
- module.cacheCredentials(function () {
+ mode.cacheCredentials(function () {
run();
});
@@ -820,8 +820,7 @@ Zotero.Sync.Storage = new function () {
}
- this.checkServer = function (moduleName, callback) {
- var module = getModuleFromName(moduleName);
+ this.checkServer = function (modeName, callback) {
Zotero.Sync.Storage.EventManager.registerObserver({
onSuccess: function () {},
onError: function (e) {
@@ -833,47 +832,16 @@ Zotero.Sync.Storage = new function () {
return true;
}
}, false, "checkServer");
- return module.checkServer(function (uri, status) {
+
+ var mode = getModeFromName(modeName);
+ return mode.checkServer(function (uri, status) {
callback(uri, status, function () {
- module.checkServerCallback(uri, status);
+ mode.checkServerCallback(uri, status);
});
});
}
- this.purgeDeletedStorageFiles = function (moduleName, callback) {
- var module = getModuleFromName(moduleName);
- if (!module.active) {
- return;
- }
- Zotero.Sync.Storage.EventManager.registerObserver({
- onError: function (e) {
- error(e);
- }
- }, false, "purgeDeletedStorageFiles");
- module.purgeDeletedStorageFiles(callback);
- }
-
-
- this.purgeOrphanedStorageFiles = function (moduleName, callback) {
- var module = getModuleFromName(moduleName);
- if (!module.active) {
- return;
- }
- Zotero.Sync.Storage.EventManager.registerObserver({
- onError: function (e) {
- error(e);
- }
- }, false, "purgeOrphanedStorageFiles");
- module.purgeOrphanedStorageFiles(callback);
- }
-
-
- this.isActive = function (moduleName) {
- return getModuleFromName(moduleName).active;
- }
-
-
this.resetAllSyncStates = function (syncState, includeUserFiles, includeGroupFiles) {
if (!includeUserFiles && !includeGroupFiles) {
includeUserFiles = true;
@@ -922,12 +890,12 @@ Zotero.Sync.Storage = new function () {
//
// Private methods
//
- function getModuleFromName(moduleName) {
- return new Zotero.Sync.Storage.Module(moduleName);
+ function getModeFromName(modeName) {
+ return Zotero.Sync.Storage[modeName];
}
- function getModuleFromLibrary(libraryID) {
+ function getModeFromLibrary(libraryID) {
if (libraryID === undefined) {
throw new Error("libraryID not provided");
}
@@ -942,10 +910,10 @@ Zotero.Sync.Storage = new function () {
var protocol = Zotero.Prefs.get('sync.storage.protocol');
switch (protocol) {
case 'zotero':
- return getModuleFromName('ZFS');
+ return getModeFromName('ZFS');
case 'webdav':
- return getModuleFromName('WebDAV');
+ return getModeFromName('WebDAV');
default:
throw new Error("Invalid storage protocol '" + protocol + "'");
@@ -958,7 +926,7 @@ Zotero.Sync.Storage = new function () {
return false;
}
- return getModuleFromName('ZFS');
+ return getModeFromName('ZFS');
}
}
@@ -968,13 +936,13 @@ Zotero.Sync.Storage = new function () {
*
* @return {Boolean}
*/
- function _downloadFiles(module) {
+ function _downloadFiles(mode) {
if (!_syncInProgress) {
_syncInProgress = true;
}
- var includeUserFiles = module.includeUserFiles && Zotero.Sync.Storage.downloadOnSync();
- var includeGroupFiles = module.includeGroupFiles && Zotero.Sync.Storage.downloadOnSync('groups');
+ var includeUserFiles = mode.includeUserFiles && Zotero.Sync.Storage.downloadOnSync();
+ var includeGroupFiles = mode.includeGroupFiles && Zotero.Sync.Storage.downloadOnSync('groups');
if (!includeUserFiles && !includeGroupFiles) {
Zotero.debug("No libraries are enabled for on-sync downloading");
@@ -1005,7 +973,7 @@ Zotero.Sync.Storage = new function () {
item.libraryID + '/' + item.key,
{
onStart: function (request) {
- module.downloadFile(request);
+ mode.downloadFile(request);
}
}
);
@@ -1021,12 +989,12 @@ Zotero.Sync.Storage = new function () {
*
* @return {Boolean}
*/
- function _uploadFiles(module) {
+ function _uploadFiles(mode) {
if (!_syncInProgress) {
_syncInProgress = true;
}
- var uploadFileIDs = _getFilesToUpload(module.includeUserFiles, module.includeGroupFiles);
+ var uploadFileIDs = _getFilesToUpload(mode.includeUserFiles, mode.includeGroupFiles);
if (!uploadFileIDs) {
Zotero.debug("No files to upload");
return false;
@@ -1044,7 +1012,7 @@ Zotero.Sync.Storage = new function () {
item.libraryID + '/' + item.key,
{
onStart: function (request) {
- module.uploadFile(request);
+ mode.uploadFile(request);
}
}
);
@@ -1688,7 +1656,7 @@ Zotero.Sync.Storage = new function () {
}
- function registerDefaultObserver(moduleName) {
+ function registerDefaultObserver(modeName) {
var finish = function (cancelled, skipSuccessFile) {
// Upload success file when done
if (!_resyncOnFinish && !skipSuccessFile) {
@@ -1698,20 +1666,20 @@ Zotero.Sync.Storage = new function () {
var uploadQueue = Zotero.Sync.Storage.QueueManager.get('upload', true);
var useLastSyncTime = !uploadQueue || (!cancelled && uploadQueue.lastTotalRequests == 0);
- getModuleFromName(moduleName).setLastSyncTime(function () {
+ getModeFromName(modeName).setLastSyncTime(function () {
finish(cancelled, true);
}, useLastSyncTime);
return false;
}
- Zotero.debug(moduleName + " sync is complete");
+ Zotero.debug(modeName + " sync is complete");
_syncInProgress = false;
if (_resyncOnFinish) {
Zotero.debug("Force-resyncing items in conflict");
_resyncOnFinish = false;
- Zotero.Sync.Storage.sync(moduleName);
+ Zotero.Sync.Storage.sync(modeName);
return false;
}
diff --git a/chrome/content/zotero/xpcom/storage/eventManager.js b/chrome/content/zotero/xpcom/storage/eventManager.js
@@ -130,7 +130,7 @@ Zotero.Sync.Storage.EventManager = (function () {
var queues = Zotero.Sync.Storage.QueueManager.getAll();
for each(var queue in queues) {
if (queue.isRunning()) {
- Zotero.debug(queue[0].toUpperCase() + queue.substr(1)
+ Zotero.debug(queue.name[0].toUpperCase() + queue.name.substr(1)
+ " queue not empty -- not clearing storage sync event observers");
return;
}
diff --git a/chrome/content/zotero/xpcom/storage/mode.js b/chrome/content/zotero/xpcom/storage/mode.js
@@ -0,0 +1,184 @@
+/*
+ ***** BEGIN LICENSE BLOCK *****
+
+ Copyright © 2009 Center for History and New Media
+ George Mason University, Fairfax, Virginia, USA
+ http://zotero.org
+
+ This file is part of Zotero.
+
+ Zotero is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Zotero is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with Zotero. If not, see <http://www.gnu.org/licenses/>.
+
+ ***** END LICENSE BLOCK *****
+*/
+
+
+Zotero.Sync.Storage.Mode = function () {};
+
+Zotero.Sync.Storage.Mode.prototype.__defineGetter__('enabled', function () {
+ try {
+ return this._enabled;
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+});
+
+Zotero.Sync.Storage.Mode.prototype.__defineGetter__('verified', function () {
+ try {
+ return this._verified;
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+});
+
+Zotero.Sync.Storage.Mode.prototype.__defineGetter__('active', function () {
+ try {
+ return this._enabled && this._verified && this._initFromPrefs();
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+});
+
+Zotero.Sync.Storage.Mode.prototype.__defineGetter__('username', function () {
+ try {
+ return this._username;
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+});
+
+Zotero.Sync.Storage.Mode.prototype.__defineGetter__('password', function () {
+ try {
+ return this._password;
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+});
+
+Zotero.Sync.Storage.Mode.prototype.__defineSetter__('password', function (val) {
+ try {
+ this._password = val;
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+});
+
+Zotero.Sync.Storage.Mode.prototype.init = function () {
+ try {
+ return this._init();
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.initFromPrefs = function () {
+ try {
+ return this._initFromPrefs();
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.sync = function (observer) {
+ Zotero.Sync.Storage.sync(this.name, observer);
+}
+
+Zotero.Sync.Storage.Mode.prototype.downloadFile = function (request) {
+ try {
+ this._downloadFile(request);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.uploadFile = function (request) {
+ try {
+ this._uploadFile(request);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.getLastSyncTime = function (callback) {
+ try {
+ this._getLastSyncTime(callback);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.setLastSyncTime = function (callback, useLastSyncTime) {
+ try {
+ this._setLastSyncTime(callback, useLastSyncTime);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.checkServer = function (callback) {
+ try {
+ return this._checkServer(callback);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.checkServerCallback = function (uri, status, window, skipSuccessMessage) {
+ try {
+ return this._checkServerCallback(uri, status, window, skipSuccessMessage);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.cacheCredentials = function (callback) {
+ try {
+ return this._cacheCredentials(callback);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.purgeDeletedStorageFiles = function (callback) {
+ try {
+ this._purgeDeletedStorageFiles(callback);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
+
+Zotero.Sync.Storage.Mode.prototype.purgeOrphanedStorageFiles = function (callback) {
+ try {
+ this._purgeOrphanedStorageFiles(callback);
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+}
diff --git a/chrome/content/zotero/xpcom/storage/module.js b/chrome/content/zotero/xpcom/storage/module.js
@@ -1,198 +0,0 @@
-/*
- ***** BEGIN LICENSE BLOCK *****
-
- Copyright © 2009 Center for History and New Media
- George Mason University, Fairfax, Virginia, USA
- http://zotero.org
-
- This file is part of Zotero.
-
- Zotero is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Zotero is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Zotero. If not, see <http://www.gnu.org/licenses/>.
-
- ***** END LICENSE BLOCK *****
-*/
-
-
-Zotero.Sync.Storage.Module = function (moduleName) {
- switch (moduleName) {
- case 'ZFS':
- this._module = Zotero.Sync.Storage.Module.ZFS;
- break;
-
- case 'WebDAV':
- this._module = Zotero.Sync.Storage.Module.WebDAV;
- break;
-
- default:
- throw ("Invalid storage session module '" + moduleName + "'");
- }
-};
-
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('name', function () this._module.name);
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('includeUserFiles', function () this._module.includeUserFiles);
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('includeGroupFiles', function () this._module.includeGroupFiles);
-
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('enabled', function () {
- try {
- return this._module.enabled;
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-});
-
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('verified', function () {
- try {
- return this._module.verified;
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-});
-
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('active', function () {
- try {
- return this._module.enabled && this._module.initFromPrefs() && this._module.verified;
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-});
-
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('username', function () {
- try {
- return this._module.username;
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-});
-
-Zotero.Sync.Storage.Module.prototype.__defineGetter__('password', function () {
- try {
- return this._module.password;
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-});
-
-Zotero.Sync.Storage.Module.prototype.__defineSetter__('password', function (val) {
- try {
- this._module.password = val;
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-});
-
-
-Zotero.Sync.Storage.Module.prototype.init = function () {
- try {
- return this._module.init();
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.initFromPrefs = function () {
- try {
- return this._module.initFromPrefs();
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.downloadFile = function (request) {
- try {
- this._module.downloadFile(request);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.uploadFile = function (request) {
- try {
- this._module.uploadFile(request);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.getLastSyncTime = function (callback) {
- try {
- this._module.getLastSyncTime(callback);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.setLastSyncTime = function (callback, useLastSyncTime) {
- try {
- this._module.setLastSyncTime(callback, useLastSyncTime);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.checkServer = function (callback) {
- try {
- return this._module.checkServer(callback);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.checkServerCallback = function (uri, status, window, skipSuccessMessage) {
- try {
- return this._module.checkServerCallback(uri, status, window, skipSuccessMessage);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.cacheCredentials = function (callback) {
- try {
- return this._module.cacheCredentials(callback);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.purgeDeletedStorageFiles = function (callback) {
- try {
- this._module.purgeDeletedStorageFiles(callback);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
-
-Zotero.Sync.Storage.Module.prototype.purgeOrphanedStorageFiles = function (callback) {
- try {
- this._module.purgeOrphanedStorageFiles(callback);
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
-}
diff --git a/chrome/content/zotero/xpcom/storage/webdav.js b/chrome/content/zotero/xpcom/storage/webdav.js
@@ -24,7 +24,7 @@
*/
-Zotero.Sync.Storage.Module.WebDAV = (function () {
+Zotero.Sync.Storage.WebDAV = (function () {
// TEMP
// TODO: localize
var _defaultError = "A WebDAV file sync error occurred. Please try syncing again.\n\nIf you receive this message repeatedly, check your WebDAV server settings in the Sync pane of the Zotero preferences.";
@@ -387,7 +387,7 @@ Zotero.Sync.Storage.Module.WebDAV = (function () {
* Create a Zotero directory on the storage server
*/
function createServerDirectory(callback) {
- var uri = Zotero.Sync.Storage.Module.WebDAV.rootURI;
+ var uri = Zotero.Sync.Storage.WebDAV.rootURI;
Zotero.HTTP.WebDAV.doMkCol(uri, function (req) {
Zotero.debug(req.responseText);
Zotero.debug(req.status);
@@ -429,7 +429,7 @@ Zotero.Sync.Storage.Module.WebDAV = (function () {
* @return {nsIURI} URI of file on storage server
*/
function getItemURI(item) {
- var uri = Zotero.Sync.Storage.Module.WebDAV.rootURI;
+ var uri = Zotero.Sync.Storage.WebDAV.rootURI;
uri.spec = uri.spec + item.key + '.zip';
return uri;
}
@@ -443,7 +443,7 @@ Zotero.Sync.Storage.Module.WebDAV = (function () {
* @return {nsIURI} URI of property file on storage server
*/
function getItemPropertyURI(item) {
- var uri = Zotero.Sync.Storage.Module.WebDAV.rootURI;
+ var uri = Zotero.Sync.Storage.WebDAV.rootURI;
uri.spec = uri.spec + item.key + '.prop';
return uri;
}
@@ -670,31 +670,37 @@ Zotero.Sync.Storage.Module.WebDAV = (function () {
}
- return {
- name: "WebDAV",
-
- get includeUserFiles() {
+ //
+ // Public methods (called via Zotero.Sync.Storage.WebDAV)
+ //
+ var obj = new Zotero.Sync.Storage.Mode;
+ obj.name = "WebDAV";
+
+ Object.defineProperty(obj, "includeUserFiles", {
+ get: function () {
return Zotero.Prefs.get("sync.storage.enabled") && Zotero.Prefs.get("sync.storage.protocol") == 'webdav';
- },
- includeGroupItems: false,
-
- get enabled() {
- return this.includeUserFiles;
- },
-
- get verified() {
- return Zotero.Prefs.get("sync.storage.verified");
- },
-
- get username() {
- return Zotero.Prefs.get('sync.storage.username');
- },
+ }
+ });
+ obj.includeGroupItems = false;
- get password() {
- var username = this.username;
+ Object.defineProperty(obj, "_enabled", {
+ get: function () this.includeUserFiles
+ });
+
+ Object.defineProperty(obj, "_verified", {
+ get: function () Zotero.Prefs.get("sync.storage.verified")
+ });
+
+ Object.defineProperty(obj, "_username", {
+ get: function () Zotero.Prefs.get('sync.storage.username')
+ });
+
+ Object.defineProperty(obj, "_password", {
+ get: function () {
+ var username = this._username;
if (!username) {
- Zotero.debug('Username not set before getting Zotero.Sync.Storage.Module.WebDAV.password');
+ Zotero.debug('Username not set before getting Zotero.Sync.Storage.WebDAV.password');
return '';
}
@@ -713,10 +719,10 @@ Zotero.Sync.Storage.Module.WebDAV = (function () {
return '';
},
- set password(password) {
- var username = this.username;
+ set: function (password) {
+ var username = this._username;
if (!username) {
- Zotero.debug('Username not set before setting Zotero.Sync.Server.Module.WebDAV.password');
+ Zotero.debug('Username not set before setting Zotero.Sync.Server.Mode.WebDAV.password');
return;
}
@@ -740,419 +746,552 @@ Zotero.Sync.Storage.Module.WebDAV = (function () {
null, username, password, "", "");
loginManager.addLogin(loginInfo);
}
- },
-
- get rootURI() {
+ }
+ });
+
+ Object.defineProperty(obj, "rootURI", {
+ get: function () {
if (!_rootURI) {
throw new Error("Root URI not initialized");
}
return _rootURI.clone();
- },
-
- get parentURI() {
+ }
+ });
+
+ Object.defineProperty(obj, "parentURI", {
+ get: function () {
if (!_parentURI) {
throw new Error("Parent URI not initialized");
}
return _parentURI.clone();
- },
+ }
+ });
+
+ obj._init = function (url, dir, username, password) {
+ if (!url) {
+ var msg = "WebDAV URL not provided";
+ Zotero.debug(msg);
+ throw ({
+ message: msg,
+ name: "Z_ERROR_NO_URL",
+ filename: "webdav.js",
+ toString: function () { return this.message; }
+ });
+ }
+ if (username && !password) {
+ var msg = "WebDAV password not provided";
+ Zotero.debug(msg);
+ throw ({
+ message: msg,
+ name: "Z_ERROR_NO_PASSWORD",
+ filename: "webdav.js",
+ toString: function () { return this.message; }
+ });
+ }
- init: function (url, dir, username, password) {
- if (!url) {
- var msg = "WebDAV URL not provided";
- Zotero.debug(msg);
- throw ({
- message: msg,
- name: "Z_ERROR_NO_URL",
- filename: "webdav.js",
- toString: function () { return this.message; }
- });
- }
-
- if (username && !password) {
- var msg = "WebDAV password not provided";
- Zotero.debug(msg);
- throw ({
- message: msg,
- name: "Z_ERROR_NO_PASSWORD",
- filename: "webdav.js",
- toString: function () { return this.message; }
- });
- }
-
- var ios = Components.classes["@mozilla.org/network/io-service;1"].
- getService(Components.interfaces.nsIIOService);
- try {
- var uri = ios.newURI(url, null, null);
- if (username) {
- uri.username = username;
- uri.password = password;
- }
- }
- catch (e) {
- Zotero.debug(e);
- Components.utils.reportError(e);
- return false;
- }
- if (!uri.spec.match(/\/$/)) {
- uri.spec += "/";
+ var ios = Components.classes["@mozilla.org/network/io-service;1"].
+ getService(Components.interfaces.nsIIOService);
+ try {
+ var uri = ios.newURI(url, null, null);
+ if (username) {
+ uri.username = username;
+ uri.password = password;
}
- _parentURI = uri;
+ }
+ catch (e) {
+ Zotero.debug(e);
+ Components.utils.reportError(e);
+ return false;
+ }
+ if (!uri.spec.match(/\/$/)) {
+ uri.spec += "/";
+ }
+ _parentURI = uri;
+
+ var uri = uri.clone();
+ uri.spec += "zotero/";
+ _rootURI = uri;
+ return true;
+ };
+
+
+ obj._initFromPrefs = function () {
+ var scheme = Zotero.Prefs.get('sync.storage.scheme');
+ switch (scheme) {
+ case 'http':
+ case 'https':
+ break;
- var uri = uri.clone();
- uri.spec += "zotero/";
- _rootURI = uri;
- return true;
- },
+ default:
+ throw new Error("Invalid WebDAV scheme '" + scheme + "'");
+ }
+ var url = Zotero.Prefs.get('sync.storage.url');
+ if (!url) {
+ return false;
+ }
- initFromPrefs: function () {
- var scheme = Zotero.Prefs.get('sync.storage.scheme');
- switch (scheme) {
- case 'http':
- case 'https':
- break;
-
- default:
- throw new Error("Invalid WebDAV scheme '" + scheme + "'");
- }
-
- var url = Zotero.Prefs.get('sync.storage.url');
- if (!url) {
- return false;
- }
-
- url = scheme + '://' + url;
- var dir = "zotero";
- var username = this.username;
- var password = this.password;
-
- return this.init(url, dir, username, password);
- },
+ url = scheme + '://' + url;
+ var dir = "zotero";
+ var username = this._username;
+ var password = this._password;
+ return this._init(url, dir, username, password);
+ };
+
+
+ /**
+ * Begin download process for individual file
+ *
+ * @param {Zotero.Sync.Storage.Request} [request]
+ */
+ obj._downloadFile = function (request) {
+ var item = Zotero.Sync.Storage.getItemFromRequestName(request.name);
+ if (!item) {
+ throw new Error("Item '" + request.name + "' not found");
+ }
- /**
- * Begin download process for individual file
- *
- * @param {Zotero.Sync.Storage.Request} [request]
- */
- downloadFile: function (request) {
- var item = Zotero.Sync.Storage.getItemFromRequestName(request.name);
- if (!item) {
- throw new Error("Item '" + request.name + "' not found");
+ // Retrieve modification time from server to store locally afterwards
+ getStorageModificationTime(item, function (item, mdate) {
+ if (!request.isRunning()) {
+ Zotero.debug("Download request '" + request.name
+ + "' is no longer running after getting mod time");
+ return;
}
- // Retrieve modification time from server to store locally afterwards
- getStorageModificationTime(item, function (item, mdate) {
- if (!request.isRunning()) {
- Zotero.debug("Download request '" + request.name
- + "' is no longer running after getting mod time");
- return;
- }
+ if (!mdate) {
+ Zotero.debug("Remote file not found for item " + Zotero.Items.getLibraryKeyHash(item));
+ request.finish();
+ return;
+ }
+
+ try {
+ var syncModTime = mdate.getTime();
- if (!mdate) {
- Zotero.debug("Remote file not found for item " + Zotero.Items.getLibraryKeyHash(item));
+ // Skip download if local file exists and matches mod time
+ var file = item.getFile();
+ if (file && file.exists() && syncModTime == file.lastModifiedTime) {
+ Zotero.debug("File mod time matches remote file -- skipping download");
+
+ Zotero.DB.beginTransaction();
+ var syncState = Zotero.Sync.Storage.getSyncState(item.id);
+ var updateItem = syncState != 1;
+ Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
+ Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_IN_SYNC);
+ Zotero.DB.commitTransaction();
+ onChangesMade();
request.finish();
return;
}
- try {
- var syncModTime = mdate.getTime();
-
- // Skip download if local file exists and matches mod time
- var file = item.getFile();
- if (file && file.exists() && syncModTime == file.lastModifiedTime) {
- Zotero.debug("File mod time matches remote file -- skipping download");
-
- Zotero.DB.beginTransaction();
- var syncState = Zotero.Sync.Storage.getSyncState(item.id);
- var updateItem = syncState != 1;
- Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
- Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_IN_SYNC);
- Zotero.DB.commitTransaction();
- onChangesMade();
- request.finish();
- return;
- }
-
- var uri = getItemURI(item);
- var destFile = Zotero.getTempDirectory();
- destFile.append(item.key + '.zip.tmp');
- if (destFile.exists()) {
- destFile.remove(false);
- }
-
- var listener = new Zotero.Sync.Storage.StreamListener(
- {
- onStart: function (request, data) {
- if (data.request.isFinished()) {
- Zotero.debug("Download request " + data.request.name
- + " stopped before download started -- closing channel");
- request.cancel(0x804b0002); // NS_BINDING_ABORTED
- return;
- }
- },
- onProgress: function (a, b, c) {
- request.onProgress(a, b, c)
- },
- onStop: function (request, status, response, data) {
- if (status == 404) {
- var msg = "Remote ZIP file not found for item " + item.key;
- Zotero.debug(msg, 2);
- Components.utils.reportError(msg);
-
- // Delete the orphaned prop file
- deleteStorageFiles([item.key + ".prop"]);
-
- data.request.finish();
- return;
- }
- else if (status != 200) {
- var msg = "Unexpected status code " + status
- + " for request " + data.request.name
- + " in Zotero.Sync.Storage.Module.WebDAV.downloadFile()";
- Zotero.debug(msg, 1);
- Components.utils.reportError(msg);
- Zotero.Sync.Storage.EventManager.error(_defaultError);
- }
-
- // Don't try to process if the request has been cancelled
- if (data.request.isFinished()) {
- Zotero.debug("Download request " + data.request.name
- + " is no longer running after file download");
- return;
- }
-
- Zotero.debug("Finished download of " + destFile.path);
-
- try {
- Zotero.Sync.Storage.processDownload(data);
- data.request.finish();
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
- },
- request: request,
- item: item,
- compressed: true,
- syncModTime: syncModTime
- }
- );
-
- // Don't display password in console
- var disp = uri.clone();
- if (disp.password) {
- disp.password = '********';
- }
- Zotero.debug('Saving ' + disp.spec + ' with saveURI()');
- const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
- var wbp = Components
- .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
- .createInstance(nsIWBP);
- wbp.persistFlags = nsIWBP.PERSIST_FLAGS_BYPASS_CACHE;
- wbp.progressListener = listener;
- wbp.saveURI(uri, null, null, null, null, destFile);
- }
- catch (e) {
- request.error(e);
+ var uri = getItemURI(item);
+ var destFile = Zotero.getTempDirectory();
+ destFile.append(item.key + '.zip.tmp');
+ if (destFile.exists()) {
+ destFile.remove(false);
}
- });
- },
-
-
- uploadFile: function (request) {
- Zotero.Sync.Storage.createUploadFile(request, function (data) { processUploadFile(data); });
- },
-
-
- getLastSyncTime: function (callback) {
- // Cache the credentials at the root URI
- var self = this;
- this.cacheCredentials(function () {
- try {
- var uri = this.rootURI;
- var successFileURI = uri.clone();
- successFileURI.spec += "lastsync";
- Zotero.HTTP.doGet(successFileURI, function (req) {
- var ts = undefined;
- try {
- if (req.responseText) {
- Zotero.debug(req.responseText);
+
+ var listener = new Zotero.Sync.Storage.StreamListener(
+ {
+ onStart: function (request, data) {
+ if (data.request.isFinished()) {
+ Zotero.debug("Download request " + data.request.name
+ + " stopped before download started -- closing channel");
+ request.cancel(0x804b0002); // NS_BINDING_ABORTED
+ return;
}
- Zotero.debug(req.status);
-
- if (req.status == 403) {
- Zotero.debug("Clearing WebDAV authentication credentials", 2);
- _cachedCredentials = false;
+ },
+ onProgress: function (a, b, c) {
+ request.onProgress(a, b, c)
+ },
+ onStop: function (request, status, response, data) {
+ if (status == 404) {
+ var msg = "Remote ZIP file not found for item " + item.key;
+ Zotero.debug(msg, 2);
+ Components.utils.reportError(msg);
+
+ // Delete the orphaned prop file
+ deleteStorageFiles([item.key + ".prop"]);
+
+ data.request.finish();
+ return;
}
-
- if (req.status != 200 && req.status != 404) {
- var msg = "Unexpected status code " + req.status + " for HEAD request "
- + "in Zotero.Sync.Storage.Module.WebDAV.getLastSyncTime()";
+ else if (status != 200) {
+ var msg = "Unexpected status code " + status
+ + " for request " + data.request.name
+ + " in Zotero.Sync.Storage.WebDAV.downloadFile()";
Zotero.debug(msg, 1);
Components.utils.reportError(msg);
Zotero.Sync.Storage.EventManager.error(_defaultError);
}
- if (req.status == 200) {
- var lastModified = req.getResponseHeader("Last-Modified");
- var date = new Date(lastModified);
- Zotero.debug("Last successful storage sync was " + date);
- ts = Zotero.Date.toUnixTimestamp(date);
- }
- else {
- ts = null;
+ // Don't try to process if the request has been cancelled
+ if (data.request.isFinished()) {
+ Zotero.debug("Download request " + data.request.name
+ + " is no longer running after file download");
+ return;
}
- callback(ts);
- }
- catch(e) {
- Zotero.debug(e, 1);
- Components.utils.reportError(e);
- Zotero.Sync.Storage.EventManager.error(_defaultError);
- }
- });
- return;
- }
- catch (e) {
- Zotero.debug(e);
- Components.utils.reportError(e);
- Zotero.Sync.Storage.EventManager.error(_defaultError);
+ Zotero.debug("Finished download of " + destFile.path);
+
+ try {
+ Zotero.Sync.Storage.processDownload(data);
+ data.request.finish();
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+ },
+ request: request,
+ item: item,
+ compressed: true,
+ syncModTime: syncModTime
+ }
+ );
+
+ // Don't display password in console
+ var disp = uri.clone();
+ if (disp.password) {
+ disp.password = '********';
}
- });
- },
-
-
- setLastSyncTime: function (callback) {
+ Zotero.debug('Saving ' + disp.spec + ' with saveURI()');
+ const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
+ var wbp = Components
+ .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+ .createInstance(nsIWBP);
+ wbp.persistFlags = nsIWBP.PERSIST_FLAGS_BYPASS_CACHE;
+ wbp.progressListener = listener;
+ wbp.saveURI(uri, null, null, null, null, destFile);
+ }
+ catch (e) {
+ request.error(e);
+ }
+ });
+ };
+
+
+ obj._uploadFile = function (request) {
+ Zotero.Sync.Storage.createUploadFile(request, function (data) { processUploadFile(data); });
+ };
+
+
+ obj._getLastSyncTime = function (callback) {
+ // Cache the credentials at the root URI
+ var self = this;
+ this._cacheCredentials(function () {
try {
var uri = this.rootURI;
var successFileURI = uri.clone();
successFileURI.spec += "lastsync";
-
- Zotero.HTTP.WebDAV.doPut(successFileURI, " ", function (req) {
- Zotero.debug(req.responseText);
- Zotero.debug(req.status);
-
- switch (req.status) {
- case 200:
- case 201:
- case 204:
- getLastSyncTime(function (ts) {
- if (ts) {
- var sql = "REPLACE INTO version VALUES ('storage_webdav', ?)";
- Zotero.DB.query(sql, { int: ts });
- }
- if (callback) {
- callback();
- }
- });
- return;
+ Zotero.HTTP.doGet(successFileURI, function (req) {
+ var ts = undefined;
+ try {
+ if (req.responseText) {
+ Zotero.debug(req.responseText);
+ }
+ Zotero.debug(req.status);
+
+ if (req.status == 403) {
+ Zotero.debug("Clearing WebDAV authentication credentials", 2);
+ _cachedCredentials = false;
+ }
+
+ if (req.status != 200 && req.status != 404) {
+ var msg = "Unexpected status code " + req.status + " for HEAD request "
+ + "in Zotero.Sync.Storage.WebDAV.getLastSyncTime()";
+ Zotero.debug(msg, 1);
+ Components.utils.reportError(msg);
+ Zotero.Sync.Storage.EventManager.error(_defaultError);
+ }
+
+ if (req.status == 200) {
+ var lastModified = req.getResponseHeader("Last-Modified");
+ var date = new Date(lastModified);
+ Zotero.debug("Last successful storage sync was " + date);
+ ts = Zotero.Date.toUnixTimestamp(date);
+ }
+ else {
+ ts = null;
+ }
+
+ callback(ts);
}
-
- var msg = "Unexpected error code " + req.status + " uploading storage success file";
- Zotero.debug(msg, 2);
- Components.utils.reportError(msg);
- if (callback) {
- callback();
+ catch(e) {
+ Zotero.debug(e, 1);
+ Components.utils.reportError(e);
+ Zotero.Sync.Storage.EventManager.error(_defaultError);
}
});
+ return;
}
catch (e) {
Zotero.debug(e);
Components.utils.reportError(e);
- if (callback) {
- callback();
- }
- return;
- }
- },
-
-
- cacheCredentials: function (callback) {
- if (_cachedCredentials) {
- Zotero.debug("Credentials are already cached");
- setTimeout(function () {
- callback();
- }, 0);
- return false;
+ Zotero.Sync.Storage.EventManager.error(_defaultError);
}
+ });
+ };
+
+
+ obj._setLastSyncTime = function (callback) {
+ try {
+ var uri = this.rootURI;
+ var successFileURI = uri.clone();
+ successFileURI.spec += "lastsync";
- Zotero.HTTP.doOptions(this.rootURI, function (req) {
- checkResponse(req);
+ Zotero.HTTP.WebDAV.doPut(successFileURI, " ", function (req) {
+ Zotero.debug(req.responseText);
+ Zotero.debug(req.status);
+
+ switch (req.status) {
+ case 200:
+ case 201:
+ case 204:
+ getLastSyncTime(function (ts) {
+ if (ts) {
+ var sql = "REPLACE INTO version VALUES ('storage_webdav', ?)";
+ Zotero.DB.query(sql, { int: ts });
+ }
+ if (callback) {
+ callback();
+ }
+ });
+ return;
+ }
- if (req.status != 200) {
- var msg = "Unexpected status code " + req.status + " for OPTIONS request "
- + "in Zotero.Sync.Storage.Module.WebDAV.getLastSyncTime()";
- Zotero.debug(msg, 1);
- Components.utils.reportError(msg);
- Zotero.Sync.Storage.EventManager.error(_defaultErrorRestart);
+ var msg = "Unexpected error code " + req.status + " uploading storage success file";
+ Zotero.debug(msg, 2);
+ Components.utils.reportError(msg);
+ if (callback) {
+ callback();
}
- Zotero.debug("Credentials are cached");
- _cachedCredentials = true;
- callback();
});
- return true;
- },
-
+ }
+ catch (e) {
+ Zotero.debug(e);
+ Components.utils.reportError(e);
+ if (callback) {
+ callback();
+ }
+ return;
+ }
+ };
+
+
+ obj._cacheCredentials = function (callback) {
+ if (_cachedCredentials) {
+ Zotero.debug("Credentials are already cached");
+ setTimeout(function () {
+ callback();
+ }, 0);
+ return false;
+ }
- /**
- * @param {Function} callback Function to pass URI and result value to
- * @param {Object} errorCallbacks
- */
- checkServer: function (callback) {
- this.initFromPrefs();
+ Zotero.HTTP.doOptions(this.rootURI, function (req) {
+ checkResponse(req);
- try {
- var parentURI = this.parentURI;
- var uri = this.rootURI;
+ if (req.status != 200) {
+ var msg = "Unexpected status code " + req.status + " for OPTIONS request "
+ + "in Zotero.Sync.Storage.WebDAV.getLastSyncTime()";
+ Zotero.debug(msg, 1);
+ Components.utils.reportError(msg);
+ Zotero.Sync.Storage.EventManager.error(_defaultErrorRestart);
}
- catch (e) {
- switch (e.name) {
- case 'Z_ERROR_NO_URL':
- callback(null, Zotero.Sync.Storage.ERROR_NO_URL);
- return;
-
- case 'Z_ERROR_NO_PASSWORD':
- callback(null, Zotero.Sync.Storage.ERROR_NO_PASSWORD);
- return;
-
- default:
- Zotero.debug(e);
- Components.utils.reportError(e);
- callback(null, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
- }
+ Zotero.debug("Credentials are cached");
+ _cachedCredentials = true;
+ callback();
+ });
+ return true;
+ };
+
+
+ /**
+ * @param {Function} callback Function to pass URI and result value to
+ * @param {Object} errorCallbacks
+ */
+ obj._checkServer = function (callback) {
+ this._initFromPrefs();
+
+ try {
+ var parentURI = this.parentURI;
+ var uri = this.rootURI;
+ }
+ catch (e) {
+ switch (e.name) {
+ case 'Z_ERROR_NO_URL':
+ callback(null, Zotero.Sync.Storage.ERROR_NO_URL);
+ return;
+
+ case 'Z_ERROR_NO_PASSWORD':
+ callback(null, Zotero.Sync.Storage.ERROR_NO_PASSWORD);
+ return;
+
+ default:
+ Zotero.debug(e);
+ Components.utils.reportError(e);
+ callback(null, Zotero.Sync.Storage.ERROR_UNKNOWN);
+ return;
+ }
+ }
+
+ var requestHolder = { request: null };
+
+ var prolog = '<?xml version="1.0" encoding="utf-8" ?>\n';
+ var D = new Namespace("D", "DAV:");
+ var nsDeclarations = 'xmlns:' + D.prefix + '=' + '"' + D.uri + '"';
+
+ var requestXML = new XML('<D:propfind ' + nsDeclarations + '/>');
+ requestXML.D::prop = '';
+ // IIS 5.1 requires at least one property in PROPFIND
+ requestXML.D::prop.D::getcontentlength = '';
+
+ var xmlstr = prolog + requestXML.toXMLString();
+
+ // Test whether URL is WebDAV-enabled
+ var request = Zotero.HTTP.doOptions(uri, function (req) {
+ // Timeout
+ if (req.status == 0) {
+ checkResponse(req);
+
+ callback(uri, Zotero.Sync.Storage.ERROR_UNREACHABLE);
+ return;
}
- var requestHolder = { request: null };
+ Zotero.debug(req.getAllResponseHeaders());
+ Zotero.debug(req.responseText);
+ Zotero.debug(req.status);
- var prolog = '<?xml version="1.0" encoding="utf-8" ?>\n';
- var D = new Namespace("D", "DAV:");
- var nsDeclarations = 'xmlns:' + D.prefix + '=' + '"' + D.uri + '"';
+ switch (req.status) {
+ case 400:
+ callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
+ return;
+
+ case 401:
+ callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
+ return;
+
+ case 403:
+ callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
+ return;
+
+ case 500:
+ callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
+ return;
+ }
- var requestXML = new XML('<D:propfind ' + nsDeclarations + '/>');
- requestXML.D::prop = '';
- // IIS 5.1 requires at least one property in PROPFIND
- requestXML.D::prop.D::getcontentlength = '';
+ var dav = req.getResponseHeader("DAV");
+ if (dav == null) {
+ callback(uri, Zotero.Sync.Storage.ERROR_NOT_DAV);
+ return;
+ }
- var xmlstr = prolog + requestXML.toXMLString();
+ // Get the Authorization header used in case we need to do a request
+ // on the parent below
+ var channelAuthorization = Zotero.HTTP.getChannelAuthorization(req.channel);
- // Test whether URL is WebDAV-enabled
- var request = Zotero.HTTP.doOptions(uri, function (req) {
- // Timeout
- if (req.status == 0) {
- checkResponse(req);
-
- callback(uri, Zotero.Sync.Storage.ERROR_UNREACHABLE);
- return;
- }
-
- Zotero.debug(req.getAllResponseHeaders());
+ var headers = { Depth: 0 };
+
+ // Test whether Zotero directory exists
+ Zotero.HTTP.WebDAV.doProp("PROPFIND", uri, xmlstr, function (req) {
Zotero.debug(req.responseText);
Zotero.debug(req.status);
switch (req.status) {
+ case 207:
+ // Test if Zotero directory is writable
+ var testFileURI = uri.clone();
+ testFileURI.spec += "zotero-test-file";
+ Zotero.HTTP.WebDAV.doPut(testFileURI, " ", function (req) {
+ Zotero.debug(req.responseText);
+ Zotero.debug(req.status);
+
+ switch (req.status) {
+ case 200:
+ case 201:
+ case 204:
+ Zotero.HTTP.doGet(
+ testFileURI,
+ function (req) {
+ Zotero.debug(req.responseText);
+ Zotero.debug(req.status);
+
+ switch (req.status) {
+ case 200:
+ // Delete test file
+ Zotero.HTTP.WebDAV.doDelete(
+ testFileURI,
+ function (req) {
+ Zotero.debug(req.responseText);
+ Zotero.debug(req.status);
+
+ switch (req.status) {
+ case 200: // IIS 5.1 and Sakai return 200
+ case 204:
+ callback(uri, Zotero.Sync.Storage.SUCCESS);
+ return;
+
+ case 401:
+ callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
+ return;
+
+ case 403:
+ callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
+ return;
+
+ default:
+ callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
+ return;
+ }
+ }
+ );
+ return;
+
+ case 401:
+ callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
+ return;
+
+ case 403:
+ callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
+ return;
+
+ // IIS 6+ configured not to serve extensionless files or .prop files
+ // http://support.microsoft.com/kb/326965
+ case 404:
+ callback(uri, Zotero.Sync.Storage.ERROR_FILE_MISSING_AFTER_UPLOAD);
+ return;
+
+ case 500:
+ callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
+ return;
+
+ default:
+ callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
+ return;
+ }
+ }
+ );
+ return;
+
+ case 401:
+ callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
+ return;
+
+ case 403:
+ callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
+ return;
+
+ case 500:
+ callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
+ return;
+
+ default:
+ callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
+ return;
+ }
+ });
+ return;
+
case 400:
callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
return;
@@ -1165,530 +1304,399 @@ Zotero.Sync.Storage.Module.WebDAV = (function () {
callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
return;
- case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
- }
-
- var dav = req.getResponseHeader("DAV");
- if (dav == null) {
- callback(uri, Zotero.Sync.Storage.ERROR_NOT_DAV);
- return;
- }
-
- // Get the Authorization header used in case we need to do a request
- // on the parent below
- var channelAuthorization = Zotero.HTTP.getChannelAuthorization(req.channel);
-
- var headers = { Depth: 0 };
-
- // Test whether Zotero directory exists
- Zotero.HTTP.WebDAV.doProp("PROPFIND", uri, xmlstr, function (req) {
- Zotero.debug(req.responseText);
- Zotero.debug(req.status);
-
- switch (req.status) {
- case 207:
- // Test if Zotero directory is writable
- var testFileURI = uri.clone();
- testFileURI.spec += "zotero-test-file";
- Zotero.HTTP.WebDAV.doPut(testFileURI, " ", function (req) {
+ case 404:
+ // Include Authorization header from /zotero request,
+ // since Firefox probably won't apply it to the parent request
+ var newHeaders = {};
+ for (var header in headers) {
+ newHeaders[header] = headers[header];
+ }
+ newHeaders["Authorization"] = channelAuthorization;
+
+ // Zotero directory wasn't found, so see if at least
+ // the parent directory exists
+ Zotero.HTTP.WebDAV.doProp("PROPFIND", parentURI, xmlstr,
+ function (req) {
Zotero.debug(req.responseText);
Zotero.debug(req.status);
switch (req.status) {
- case 200:
- case 201:
- case 204:
- Zotero.HTTP.doGet(
- testFileURI,
- function (req) {
- Zotero.debug(req.responseText);
- Zotero.debug(req.status);
-
- switch (req.status) {
- case 200:
- // Delete test file
- Zotero.HTTP.WebDAV.doDelete(
- testFileURI,
- function (req) {
- Zotero.debug(req.responseText);
- Zotero.debug(req.status);
-
- switch (req.status) {
- case 200: // IIS 5.1 and Sakai return 200
- case 204:
- callback(
- uri,
- Zotero.Sync.Storage.SUCCESS
- );
- return;
-
- case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
-
- case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
-
- default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
- }
- }
- );
- return;
-
- case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
-
- case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
-
- // IIS 6+ configured not to serve extensionless files or .prop files
- // http://support.microsoft.com/kb/326965
- case 404:
- callback(uri, Zotero.Sync.Storage.ERROR_FILE_MISSING_AFTER_UPLOAD);
- return;
-
- case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
-
- default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
- }
- }
- );
+ // Parent directory existed
+ case 207:
+ callback(uri, Zotero.Sync.Storage.ERROR_ZOTERO_DIR_NOT_FOUND);
return;
- case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
+ case 400:
+ callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
return;
- case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
+ case 401:
+ callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
return;
- case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
+ // Parent directory wasn't found either
+ case 404:
+ callback(uri, Zotero.Sync.Storage.ERROR_PARENT_DIR_NOT_FOUND);
return;
default:
callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
return;
}
- });
- return;
-
- case 400:
- callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
- return;
-
- case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
-
- case 403:
- callback(uri, Zotero.Sync.Storage.ERROR_FORBIDDEN);
- return;
+ }, newHeaders);
+ return;
+
+ case 500:
+ callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
+ return;
- case 404:
- // Include Authorization header from /zotero request,
- // since Firefox probably won't apply it to the parent request
- var newHeaders = {};
- for (var header in headers) {
- newHeaders[header] = headers[header];
+ default:
+ callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
+ return;
+ }
+ }, headers);
+ });
+
+ if (!request) {
+ callback(uri, Zotero.Sync.Storage.ERROR_OFFLINE);
+ }
+
+ requestHolder.request = request;
+ return requestHolder;
+ };
+
+
+ obj._checkServerCallback = function (uri, status, window, skipSuccessMessage) {
+ var promptService =
+ Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
+ createInstance(Components.interfaces.nsIPromptService);
+ if (uri) {
+ var spec = uri.scheme + '://' + uri.hostPort + uri.path;
+ }
+
+ switch (status) {
+ case Zotero.Sync.Storage.SUCCESS:
+ if (!skipSuccessMessage) {
+ promptService.alert(
+ window,
+ Zotero.getString('sync.storage.serverConfigurationVerified'),
+ Zotero.getString('sync.storage.fileSyncSetUp')
+ );
+ }
+ Zotero.Prefs.set("sync.storage.verified", true);
+ return true;
+
+ case Zotero.Sync.Storage.ERROR_NO_URL:
+ var errorMessage = Zotero.getString('sync.storage.error.webdav.enterURL');
+ break;
+
+ case Zotero.Sync.Storage.ERROR_NO_PASSWORD:
+ var errorMessage = Zotero.getString('sync.error.enterPassword');
+ break;
+
+ case Zotero.Sync.Storage.ERROR_UNREACHABLE:
+ var errorMessage = Zotero.getString('sync.storage.error.serverCouldNotBeReached', uri.host);
+ break;
+
+ case Zotero.Sync.Storage.ERROR_NOT_DAV:
+ var errorMessage = Zotero.getString('sync.storage.error.webdav.invalidURL', spec);
+ break;
+
+ case Zotero.Sync.Storage.ERROR_AUTH_FAILED:
+ var errorTitle = Zotero.getString('general.permissionDenied');
+ var errorMessage = Zotero.localeJoin([
+ Zotero.getString('sync.storage.error.webdav.invalidLogin'),
+ Zotero.getString('sync.storage.error.checkFileSyncSettings')
+ ]);
+ break;
+
+ case Zotero.Sync.Storage.ERROR_FORBIDDEN:
+ var errorTitle = Zotero.getString('general.permissionDenied');
+ var errorMessage = Zotero.localeJoin([
+ Zotero.getString('sync.storage.error.webdav.permissionDenied', uri.path),
+ Zotero.getString('sync.storage.error.checkFileSyncSettings')
+ ]);
+ break;
+
+ case Zotero.Sync.Storage.ERROR_PARENT_DIR_NOT_FOUND:
+ var errorTitle = Zotero.getString('sync.storage.error.directoryNotFound');
+ var parentSpec = spec.replace(/\/zotero\/$/, "");
+ var errorMessage = Zotero.getString('sync.storage.error.doesNotExist', parentSpec);
+ break;
+
+ case Zotero.Sync.Storage.ERROR_ZOTERO_DIR_NOT_FOUND:
+ var create = promptService.confirmEx(
+ window,
+ Zotero.getString('sync.storage.error.directoryNotFound'),
+ Zotero.getString('sync.storage.error.doesNotExist', spec) + "\n\n"
+ + Zotero.getString('sync.storage.error.createNow'),
+ promptService.BUTTON_POS_0
+ * promptService.BUTTON_TITLE_IS_STRING
+ + promptService.BUTTON_POS_1
+ * promptService.BUTTON_TITLE_CANCEL,
+ Zotero.getString('general.create'),
+ null, null, null, {}
+ );
+
+ if (create != 0) {
+ return;
+ }
+
+ createServerDirectory(function (uri, status) {
+ switch (status) {
+ case Zotero.Sync.Storage.SUCCESS:
+ if (!skipSuccessMessage) {
+ promptService.alert(
+ window,
+ Zotero.getString('sync.storage.serverConfigurationVerified'),
+ Zotero.getString('sync.storage.fileSyncSetUp')
+ );
}
- newHeaders["Authorization"] = channelAuthorization;
-
- // Zotero directory wasn't found, so see if at least
- // the parent directory exists
- Zotero.HTTP.WebDAV.doProp("PROPFIND", this.parentURI, xmlstr,
- function (req) {
- Zotero.debug(req.responseText);
- Zotero.debug(req.status);
-
- switch (req.status) {
- // Parent directory existed
- case 207:
- callback(uri, Zotero.Sync.Storage.ERROR_ZOTERO_DIR_NOT_FOUND);
- return;
-
- case 400:
- callback(uri, Zotero.Sync.Storage.ERROR_BAD_REQUEST);
- return;
-
- case 401:
- callback(uri, Zotero.Sync.Storage.ERROR_AUTH_FAILED);
- return;
-
- // Parent directory wasn't found either
- case 404:
- callback(uri, Zotero.Sync.Storage.ERROR_PARENT_DIR_NOT_FOUND);
- return;
-
- default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
- }
- }, newHeaders);
- return;
+ Zotero.Prefs.set("sync.storage.verified", true);
+ return true;
- case 500:
- callback(uri, Zotero.Sync.Storage.ERROR_SERVER_ERROR);
- return;
-
- default:
- callback(uri, Zotero.Sync.Storage.ERROR_UNKNOWN);
- return;
+ case Zotero.Sync.Storage.ERROR_FORBIDDEN:
+ var errorTitle = Zotero.getString('general.permissionDenied');
+ var errorMessage = Zotero.getString('sync.storage.error.permissionDeniedAtAddress') + "\n\n"
+ + spec + "\n\n"
+ + Zotero.getString('sync.storage.error.checkFileSyncSettings');
+ break;
}
- }, headers);
- });
+
+ // TEMP
+ if (!errorMessage) {
+ var errorMessage = status;
+ }
+ promptService.alert(window, errorTitle, errorMessage);
+ });
+
+ return false;
- if (!request) {
- callback(uri, Zotero.Sync.Storage.ERROR_OFFLINE);
- }
+ case Zotero.Sync.Storage.ERROR_FILE_MISSING_AFTER_UPLOAD:
+ // TODO: localize
+ var errorTitle = "WebDAV Server Configuration Error";
+ var errorMessage = "Your WebDAV server must be configured to serve files without extensions "
+ + "and files with .prop extensions in order to work with Zotero.";
+ break;
- requestHolder.request = request;
- return requestHolder;
- },
+ case Zotero.Sync.Storage.ERROR_SERVER_ERROR:
+ // TODO: localize
+ var errorTitle = "WebDAV Server Configuration Error";
+ var errorMessage = "Your WebDAV server returned an internal error."
+ + "\n\n" + Zotero.getString('sync.storage.error.checkFileSyncSettings');
+ break;
+
+ case Zotero.Sync.Storage.ERROR_UNKNOWN:
+ var errorMessage = Zotero.localeJoin([
+ Zotero.getString('general.unknownErrorOccurred'),
+ Zotero.getString('sync.storage.error.checkFileSyncSettings')
+ ]);
+ break;
+ }
+ if (!skipSuccessMessage) {
+ if (!errorTitle) {
+ var errorTitle = Zotero.getString("general.error");
+ }
+ // TEMP
+ if (!errorMessage) {
+ var errorMessage = status;
+ }
+ promptService.alert(window, errorTitle, errorMessage);
+ }
+ return false;
+ };
+
+
+ /**
+ * Remove files on storage server that were deleted locally more than
+ * sync.storage.deleteDelayDays days ago
+ *
+ * @param {Function} callback Passed number of files deleted
+ */
+ obj._purgeDeletedStorageFiles = function (callback) {
+ if (!this._active) {
+ return;
+ }
- checkServerCallback: function (uri, status, window, skipSuccessMessage) {
- var promptService =
- Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
- createInstance(Components.interfaces.nsIPromptService);
- if (uri) {
- var spec = uri.scheme + '://' + uri.hostPort + uri.path;
+ Zotero.debug("Purging deleted storage files");
+ var files = Zotero.Sync.Storage.getDeletedFiles();
+ if (!files) {
+ Zotero.debug("No files to delete remotely");
+ if (callback) {
+ callback();
}
-
- switch (status) {
- case Zotero.Sync.Storage.SUCCESS:
- if (!skipSuccessMessage) {
- promptService.alert(
- window,
- Zotero.getString('sync.storage.serverConfigurationVerified'),
- Zotero.getString('sync.storage.fileSyncSetUp')
- );
- }
- Zotero.Prefs.set("sync.storage.verified", true);
- return true;
+ Zotero.Sync.Storage.EventManager.skip();
+ return;
+ }
+
+ // Add .zip extension
+ var files = files.map(function (file) file + ".zip");
+
+ deleteStorageFiles(files, function (results) {
+ // Remove deleted and nonexistent files from storage delete log
+ var toPurge = results.deleted.concat(results.missing);
+ if (toPurge.length > 0) {
+ var done = 0;
+ var maxFiles = 999;
+ var numFiles = toPurge.length;
- case Zotero.Sync.Storage.ERROR_NO_URL:
- var errorMessage = Zotero.getString('sync.storage.error.webdav.enterURL');
- break;
+ Zotero.DB.beginTransaction();
- case Zotero.Sync.Storage.ERROR_NO_PASSWORD:
- var errorMessage = Zotero.getString('sync.error.enterPassword');
- break;
+ do {
+ var chunk = toPurge.splice(0, maxFiles);
+ var sql = "DELETE FROM storageDeleteLog WHERE key IN ("
+ + chunk.map(function () '?').join() + ")";
+ Zotero.DB.query(sql, chunk);
+ done += chunk.length;
+ }
+ while (done < numFiles);
- case Zotero.Sync.Storage.ERROR_UNREACHABLE:
- var errorMessage = Zotero.getString('sync.storage.error.serverCouldNotBeReached', uri.host);
- break;
+ Zotero.DB.commitTransaction();
+ }
+
+ if (callback) {
+ callback(results.deleted.length);
+ }
+
+ Zotero.Sync.Storage.EventManager.success();
+ });
+ };
+
+
+ /**
+ * Delete orphaned storage files older than a day before last sync time
+ *
+ * @param {Function} callback
+ */
+ obj._purgeOrphanedStorageFiles = function (callback) {
+ const daysBeforeSyncTime = 1;
+
+ if (!this._active) {
+ Zotero.Sync.Storage.EventManager.skip();
+ return;
+ }
+
+ // If recently purged, skip
+ var lastpurge = Zotero.Prefs.get('lastWebDAVOrphanPurge');
+ var days = 10;
+ if (lastpurge && new Date(lastpurge * 1000) > (new Date() - (1000 * 60 * 60 * 24 * days))) {
+ Zotero.Sync.Storage.EventManager.skip();
+ return;
+ }
+
+ Zotero.debug("Purging orphaned storage files");
+
+ var uri = this.rootURI;
+ var path = uri.path;
+
+ var prolog = '<?xml version="1.0" encoding="utf-8" ?>\n';
+ var D = new Namespace("D", "DAV:");
+ var nsDeclarations = 'xmlns:' + D.prefix + '=' + '"' + D.uri + '"';
+
+ var requestXML = new XML('<D:propfind ' + nsDeclarations + '/>');
+ requestXML.D::prop = '';
+ requestXML.D::prop.D::getlastmodified = '';
+
+ var xmlstr = prolog + requestXML.toXMLString();
+
+ var lastSyncDate = new Date(Zotero.Sync.Server.lastLocalSyncTime * 1000);
+
+ Zotero.HTTP.WebDAV.doProp("PROPFIND", uri, xmlstr, function (req) {
+ Zotero.debug(req.responseText);
- case Zotero.Sync.Storage.ERROR_NOT_DAV:
- var errorMessage = Zotero.getString('sync.storage.error.webdav.invalidURL', spec);
- break;
+ var funcName = "Zotero.Sync.Storage.purgeOrphanedStorageFiles()";
+
+ // Strip XML declaration and convert to E4X
+ var xml = new XML(req.responseText.replace(/<\?xml.*\?>/, ''));
+
+ var deleteFiles = [];
+ var trailingSlash = !!path.match(/\/$/);
+ for each(var response in xml.D::response) {
+ var href = response.D::href.toString();
- case Zotero.Sync.Storage.ERROR_AUTH_FAILED:
- var errorTitle = Zotero.getString('general.permissionDenied');
- var errorMessage = Zotero.localeJoin([
- Zotero.getString('sync.storage.error.webdav.invalidLogin'),
- Zotero.getString('sync.storage.error.checkFileSyncSettings')
- ]);
- break;
+ // Strip trailing slash if there isn't one on the root path
+ if (!trailingSlash) {
+ href = href.replace(/\/$/, "")
+ }
- case Zotero.Sync.Storage.ERROR_FORBIDDEN:
- var errorTitle = Zotero.getString('general.permissionDenied');
- var errorMessage = Zotero.localeJoin([
- Zotero.getString('sync.storage.error.webdav.permissionDenied', uri.path),
- Zotero.getString('sync.storage.error.checkFileSyncSettings')
- ]);
- break;
+ // Absolute
+ if (href.match(/^https?:\/\//)) {
+ var ios = Components.classes["@mozilla.org/network/io-service;1"].
+ getService(Components.interfaces.nsIIOService);
+ var href = ios.newURI(href, null, null);
+ href = href.path;
+ }
- case Zotero.Sync.Storage.ERROR_PARENT_DIR_NOT_FOUND:
- var errorTitle = Zotero.getString('sync.storage.error.directoryNotFound');
- var parentSpec = spec.replace(/\/zotero\/$/, "");
- var errorMessage = Zotero.getString('sync.storage.error.doesNotExist', parentSpec);
- break;
+ // Skip root URI
+ if (href == path
+ // Some Apache servers respond with a "/zotero" href
+ // even for a "/zotero/" request
+ || (trailingSlash && href + '/' == path)
+ // Try URL-encoded as well, as above
+ || decodeURIComponent(href) == path) {
+ continue;
+ }
- case Zotero.Sync.Storage.ERROR_ZOTERO_DIR_NOT_FOUND:
- var create = promptService.confirmEx(
- window,
- Zotero.getString('sync.storage.error.directoryNotFound'),
- Zotero.getString('sync.storage.error.doesNotExist', spec) + "\n\n"
- + Zotero.getString('sync.storage.error.createNow'),
- promptService.BUTTON_POS_0
- * promptService.BUTTON_TITLE_IS_STRING
- + promptService.BUTTON_POS_1
- * promptService.BUTTON_TITLE_CANCEL,
- Zotero.getString('general.create'),
- null, null, null, {}
+ if (href.indexOf(path) == -1
+ // Try URL-encoded as well, in case there's a '~' or similar
+ // character in the URL and the server (e.g., Sakai) is
+ // encoding the value
+ && decodeURIComponent(href).indexOf(path) == -1) {
+ Zotero.Sync.Storage.EventManager.error(
+ "DAV:href '" + href + "' does not begin with path '"
+ + path + "' in " + funcName
);
-
- if (create != 0) {
- return;
- }
-
- createServerDirectory(function (uri, status) {
- switch (status) {
- case Zotero.Sync.Storage.SUCCESS:
- if (!skipSuccessMessage) {
- promptService.alert(
- window,
- Zotero.getString('sync.storage.serverConfigurationVerified'),
- Zotero.getString('sync.storage.fileSyncSetUp')
- );
- }
- Zotero.Prefs.set("sync.storage.verified", true);
- return true;
-
- case Zotero.Sync.Storage.ERROR_FORBIDDEN:
- var errorTitle = Zotero.getString('general.permissionDenied');
- var errorMessage = Zotero.getString('sync.storage.error.permissionDeniedAtAddress') + "\n\n"
- + spec + "\n\n"
- + Zotero.getString('sync.storage.error.checkFileSyncSettings');
- break;
- }
-
- // TEMP
- if (!errorMessage) {
- var errorMessage = status;
- }
- promptService.alert(window, errorTitle, errorMessage);
- });
-
- return false;
-
- case Zotero.Sync.Storage.ERROR_FILE_MISSING_AFTER_UPLOAD:
- // TODO: localize
- var errorTitle = "WebDAV Server Configuration Error";
- var errorMessage = "Your WebDAV server must be configured to serve files without extensions "
- + "and files with .prop extensions in order to work with Zotero.";
- break;
+ }
- case Zotero.Sync.Storage.ERROR_SERVER_ERROR:
- // TODO: localize
- var errorTitle = "WebDAV Server Configuration Error";
- var errorMessage = "Your WebDAV server returned an internal error."
- + "\n\n" + Zotero.getString('sync.storage.error.checkFileSyncSettings');
- break;
+ var matches = href.match(/[^\/]+$/);
+ if (!matches) {
+ Zotero.Sync.Storage.EventManager.error(
+ "Unexpected href '" + href + "' in " + funcName
+ )
+ }
+ var file = matches[0];
- case Zotero.Sync.Storage.ERROR_UNKNOWN:
- var errorMessage = Zotero.localeJoin([
- Zotero.getString('general.unknownErrorOccurred'),
- Zotero.getString('sync.storage.error.checkFileSyncSettings')
- ]);
- break;
- }
-
- if (!skipSuccessMessage) {
- if (!errorTitle) {
- var errorTitle = Zotero.getString("general.error");
+ if (file.indexOf('.') == 0) {
+ Zotero.debug("Skipping hidden file " + file);
+ continue;
}
- // TEMP
- if (!errorMessage) {
- var errorMessage = status;
+ if (!file.match(/\.zip$/) && !file.match(/\.prop$/)) {
+ Zotero.debug("Skipping file " + file);
+ continue;
}
- promptService.alert(window, errorTitle, errorMessage);
- }
- return false;
- },
-
-
- /**
- * Remove files on storage server that were deleted locally more than
- * sync.storage.deleteDelayDays days ago
- *
- * @param {Function} callback Passed number of files deleted
- */
- purgeDeletedStorageFiles: function (callback) {
- if (!this.active) {
- return;
- }
-
- Zotero.debug("Purging deleted storage files");
- var files = Zotero.Sync.Storage.getDeletedFiles();
- if (!files) {
- Zotero.debug("No files to delete remotely");
- if (callback) {
- callback();
+
+ var key = file.replace(/\.(zip|prop)$/, '');
+ var item = Zotero.Items.getByLibraryAndKey(null, key);
+ if (item) {
+ Zotero.debug("Skipping existing file " + file);
+ continue;
+ }
+
+ Zotero.debug("Checking orphaned file " + file);
+
+ // TODO: Parse HTTP date properly
+ var lastModified = response..*::getlastmodified.toString();
+ lastModified = Zotero.Date.strToISO(lastModified);
+ lastModified = Zotero.Date.sqlToDate(lastModified);
+
+ // Delete files older than a day before last sync time
+ var days = (lastSyncDate - lastModified) / 1000 / 60 / 60 / 24;
+
+ if (days > daysBeforeSyncTime) {
+ deleteFiles.push(file);
}
- Zotero.Sync.Storage.EventManager.skip();
- return;
}
- // Add .zip extension
- var files = files.map(function (file) file + ".zip");
-
- deleteStorageFiles(files, function (results) {
- // Remove deleted and nonexistent files from storage delete log
- var toPurge = results.deleted.concat(results.missing);
- if (toPurge.length > 0) {
- var done = 0;
- var maxFiles = 999;
- var numFiles = toPurge.length;
-
- Zotero.DB.beginTransaction();
-
- do {
- var chunk = toPurge.splice(0, maxFiles);
- var sql = "DELETE FROM storageDeleteLog WHERE key IN ("
- + chunk.map(function () '?').join() + ")";
- Zotero.DB.query(sql, chunk);
- done += chunk.length;
- }
- while (done < numFiles);
-
- Zotero.DB.commitTransaction();
- }
-
+ deleteStorageFiles(deleteFiles, function (results) {
+ Zotero.Prefs.set("lastWebDAVOrphanPurge", Math.round(new Date().getTime() / 1000))
if (callback) {
- callback(results.deleted.length);
+ callback(results);
}
-
Zotero.Sync.Storage.EventManager.success();
});
- },
-
-
- /**
- * Delete orphaned storage files older than a day before last sync time
- *
- * @param {Function} callback
- */
- purgeOrphanedStorageFiles: function (callback) {
- const daysBeforeSyncTime = 1;
-
- if (!this.active) {
- Zotero.Sync.Storage.EventManager.skip();
- return;
- }
-
- // If recently purged, skip
- var lastpurge = Zotero.Prefs.get('lastWebDAVOrphanPurge');
- var days = 10;
- if (lastpurge && new Date(lastpurge * 1000) > (new Date() - (1000 * 60 * 60 * 24 * days))) {
- Zotero.Sync.Storage.EventManager.skip();
- return;
- }
-
- Zotero.debug("Purging orphaned storage files");
-
- var uri = this.rootURI;
- var path = uri.path;
-
- var prolog = '<?xml version="1.0" encoding="utf-8" ?>\n';
- var D = new Namespace("D", "DAV:");
- var nsDeclarations = 'xmlns:' + D.prefix + '=' + '"' + D.uri + '"';
-
- var requestXML = new XML('<D:propfind ' + nsDeclarations + '/>');
- requestXML.D::prop = '';
- requestXML.D::prop.D::getlastmodified = '';
-
- var xmlstr = prolog + requestXML.toXMLString();
-
- var lastSyncDate = new Date(Zotero.Sync.Server.lastLocalSyncTime * 1000);
-
- Zotero.HTTP.WebDAV.doProp("PROPFIND", uri, xmlstr, function (req) {
- Zotero.debug(req.responseText);
-
- var funcName = "Zotero.Sync.Storage.purgeOrphanedStorageFiles()";
-
- // Strip XML declaration and convert to E4X
- var xml = new XML(req.responseText.replace(/<\?xml.*\?>/, ''));
-
- var deleteFiles = [];
- var trailingSlash = !!path.match(/\/$/);
- for each(var response in xml.D::response) {
- var href = response.D::href.toString();
-
- // Strip trailing slash if there isn't one on the root path
- if (!trailingSlash) {
- href = href.replace(/\/$/, "")
- }
-
- // Absolute
- if (href.match(/^https?:\/\//)) {
- var ios = Components.classes["@mozilla.org/network/io-service;1"].
- getService(Components.interfaces.nsIIOService);
- var href = ios.newURI(href, null, null);
- href = href.path;
- }
-
- // Skip root URI
- if (href == path
- // Some Apache servers respond with a "/zotero" href
- // even for a "/zotero/" request
- || (trailingSlash && href + '/' == path)
- // Try URL-encoded as well, as above
- || decodeURIComponent(href) == path) {
- continue;
- }
-
- if (href.indexOf(path) == -1
- // Try URL-encoded as well, in case there's a '~' or similar
- // character in the URL and the server (e.g., Sakai) is
- // encoding the value
- && decodeURIComponent(href).indexOf(path) == -1) {
- Zotero.Sync.Storage.EventManager.error(
- "DAV:href '" + href + "' does not begin with path '"
- + path + "' in " + funcName
- );
- }
-
- var matches = href.match(/[^\/]+$/);
- if (!matches) {
- Zotero.Sync.Storage.EventManager.error(
- "Unexpected href '" + href + "' in " + funcName
- )
- }
- var file = matches[0];
-
- if (file.indexOf('.') == 0) {
- Zotero.debug("Skipping hidden file " + file);
- continue;
- }
- if (!file.match(/\.zip$/) && !file.match(/\.prop$/)) {
- Zotero.debug("Skipping file " + file);
- continue;
- }
-
- var key = file.replace(/\.(zip|prop)$/, '');
- var item = Zotero.Items.getByLibraryAndKey(null, key);
- if (item) {
- Zotero.debug("Skipping existing file " + file);
- continue;
- }
-
- Zotero.debug("Checking orphaned file " + file);
-
- // TODO: Parse HTTP date properly
- var lastModified = response..*::getlastmodified.toString();
- lastModified = Zotero.Date.strToISO(lastModified);
- lastModified = Zotero.Date.sqlToDate(lastModified);
-
- // Delete files older than a day before last sync time
- var days = (lastSyncDate - lastModified) / 1000 / 60 / 60 / 24;
-
- if (days > daysBeforeSyncTime) {
- deleteFiles.push(file);
- }
- }
-
- deleteStorageFiles(deleteFiles, function (results) {
- Zotero.Prefs.set("lastWebDAVOrphanPurge", Math.round(new Date().getTime() / 1000))
- if (callback) {
- callback(results);
- }
- Zotero.Sync.Storage.EventManager.success();
- });
- }, { Depth: 1 });
- }
+ }, { Depth: 1 });
};
+
+ return obj;
}());
diff --git a/chrome/content/zotero/xpcom/storage/zfs.js b/chrome/content/zotero/xpcom/storage/zfs.js
@@ -24,7 +24,7 @@
*/
-Zotero.Sync.Storage.Module.ZFS = (function () {
+Zotero.Sync.Storage.ZFS = (function () {
var _rootURI;
var _userURI;
var _cachedCredentials = false;
@@ -40,7 +40,7 @@ Zotero.Sync.Storage.Module.ZFS = (function () {
var uri = getItemInfoURI(item);
Zotero.HTTP.doGet(uri, function (req) {
- var funcName = "Zotero.Sync.Storage.Module.ZFS.getStorageFileInfo()";
+ var funcName = "Zotero.Sync.Storage.ZFS.getStorageFileInfo()";
if (req.status == 404) {
callback(item, false);
@@ -237,7 +237,7 @@ Zotero.Sync.Storage.Module.ZFS = (function () {
}
Zotero.HTTP.doPost(uri, body, function (req) {
- var funcName = "Zotero.Sync.Storage.Module.ZFS.getFileUploadParameters()";
+ var funcName = "Zotero.Sync.Storage.ZFS.getFileUploadParameters()";
if (req.status == 413) {
var retry = req.getResponseHeader('Retry-After');
@@ -597,7 +597,7 @@ Zotero.Sync.Storage.Module.ZFS = (function () {
* @return {nsIURI} URI of file on storage server
*/
function getItemURI(item) {
- var uri = Zotero.Sync.Storage.Module.ZFS.rootURI;
+ var uri = Zotero.Sync.Storage.ZFS.rootURI;
// Be sure to mirror parameter changes to getItemInfoURI() below
uri.spec += Zotero.URI.getItemPath(item) + '/file?auth=1&iskey=1&version=1';
return uri;
@@ -612,7 +612,7 @@ Zotero.Sync.Storage.Module.ZFS = (function () {
* @return {nsIURI} URI of file on storage server with info flag
*/
function getItemInfoURI(item) {
- var uri = Zotero.Sync.Storage.Module.ZFS.rootURI;
+ var uri = Zotero.Sync.Storage.ZFS.rootURI;
uri.spec += Zotero.URI.getItemPath(item) + '/file?auth=1&iskey=1&version=1&info=1';
return uri;
}
@@ -631,435 +631,445 @@ Zotero.Sync.Storage.Module.ZFS = (function () {
}
- return {
- name: "ZFS",
-
- get includeUserFiles() {
+ //
+ // Public methods (called via Zotero.Sync.Storage.ZFS)
+ //
+ var obj = new Zotero.Sync.Storage.Mode;
+ obj.name = "ZFS";
+
+ Object.defineProperty(obj, "includeUserFiles", {
+ get: function () {
return Zotero.Prefs.get("sync.storage.enabled") && Zotero.Prefs.get("sync.storage.protocol") == 'zotero';
- },
-
- get includeGroupFiles() {
+ }
+ });
+
+ Object.defineProperty(obj, "includeGroupFiles", {
+ get: function () {
return Zotero.Prefs.get("sync.storage.groups.enabled");
- },
-
- get enabled() {
- return this.includeUserFiles || this.includeGroupFiles;
- },
-
- get verified() {
- return true;
- },
-
- get rootURI() {
+ }
+ });
+
+ Object.defineProperty(obj, "_enabled", {
+ get: function () this.includeUserFiles || this.includeGroupFiles
+ });
+
+ obj._verified = true;
+
+ Object.defineProperty(obj, "rootURI", {
+ get: function () {
if (!_rootURI) {
throw ("Root URI not initialized in Zotero.Sync.Storage.ZFS.rootURI");
}
return _rootURI.clone();
- },
-
- get userURI() {
+ }
+ });
+
+ Object.defineProperty(obj, "userURI", {
+ get: function () {
if (!_userURI) {
throw ("User URI not initialized in Zotero.Sync.Storage.ZFS.userURI");
}
return _userURI.clone();
- },
-
-
- init: function (url, username, password) {
- var ios = Components.classes["@mozilla.org/network/io-service;1"].
- getService(Components.interfaces.nsIIOService);
- try {
- var uri = ios.newURI(url, null, null);
- if (username) {
- uri.username = username;
- uri.password = password;
- }
- }
- catch (e) {
- Zotero.debug(e, 1);
- Components.utils.reportError(e);
- return false;
+ }
+ });
+
+
+ obj._init = function (url, username, password) {
+ var ios = Components.classes["@mozilla.org/network/io-service;1"].
+ getService(Components.interfaces.nsIIOService);
+ try {
+ var uri = ios.newURI(url, null, null);
+ if (username) {
+ uri.username = username;
+ uri.password = password;
}
- _rootURI = uri;
-
- uri = uri.clone();
- uri.spec += 'users/' + Zotero.userID + '/';
- _userURI = uri;
-
- return true;
- },
-
+ }
+ catch (e) {
+ Zotero.debug(e, 1);
+ Components.utils.reportError(e);
+ return false;
+ }
+ _rootURI = uri;
- initFromPrefs: function () {
- var url = ZOTERO_CONFIG.API_URL;
- var username = Zotero.Sync.Server.username;
- var password = Zotero.Sync.Server.password;
- return this.init(url, username, password);
- },
+ uri = uri.clone();
+ uri.spec += 'users/' + Zotero.userID + '/';
+ _userURI = uri;
+ return true;
+ };
+
+
+ obj._initFromPrefs = function () {
+ var url = ZOTERO_CONFIG.API_URL;
+ var username = Zotero.Sync.Server.username;
+ var password = Zotero.Sync.Server.password;
+ return this._init(url, username, password);
+ };
+
+
+ /**
+ * Begin download process for individual file
+ *
+ * @param {Zotero.Sync.Storage.Request} [request]
+ */
+ obj._downloadFile = function (request) {
+ var item = Zotero.Sync.Storage.getItemFromRequestName(request.name);
+ if (!item) {
+ throw new Error("Item '" + request.name + "' not found");
+ }
- /**
- * Begin download process for individual file
- *
- * @param {Zotero.Sync.Storage.Request} [request]
- */
- downloadFile: function (request) {
- var item = Zotero.Sync.Storage.getItemFromRequestName(request.name);
- if (!item) {
- throw new Error("Item '" + request.name + "' not found");
+ // Retrieve file info from server to store locally afterwards
+ getStorageFileInfo(item, function (item, info) {
+ if (!request.isRunning()) {
+ Zotero.debug("Download request '" + request.name
+ + "' is no longer running after getting remote file info");
+ return;
}
- // Retrieve file info from server to store locally afterwards
- getStorageFileInfo(item, function (item, info) {
- if (!request.isRunning()) {
- Zotero.debug("Download request '" + request.name
- + "' is no longer running after getting remote file info");
- return;
- }
-
- if (!info) {
- Zotero.debug("Remote file not found for item " + item.libraryID + "/" + item.key);
- request.finish();
- return;
- }
+ if (!info) {
+ Zotero.debug("Remote file not found for item " + item.libraryID + "/" + item.key);
+ request.finish();
+ return;
+ }
+
+ try {
+ var syncModTime = info.mtime;
+ var syncHash = info.hash;
- try {
- var syncModTime = info.mtime;
- var syncHash = info.hash;
-
- var file = item.getFile();
- // Skip download if local file exists and matches mod time
- if (file && file.exists()) {
- if (syncModTime == file.lastModifiedTime) {
- Zotero.debug("File mod time matches remote file -- skipping download");
-
- Zotero.DB.beginTransaction();
- var syncState = Zotero.Sync.Storage.getSyncState(item.id);
- //var updateItem = syncState != 1;
- var updateItem = false;
- Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
- Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_IN_SYNC);
- Zotero.DB.commitTransaction();
- Zotero.Sync.Storage.EventManager.changesMade();
- request.finish();
- return;
- }
- // If not compressed, check hash, in case only timestamp changed
- else if (!info.compressed && item.attachmentHash == syncHash) {
- Zotero.debug("File hash matches remote file -- skipping download");
-
- Zotero.DB.beginTransaction();
- var syncState = Zotero.Sync.Storage.getSyncState(item.id);
- //var updateItem = syncState != 1;
- var updateItem = false;
- if (!info.compressed) {
- Zotero.Sync.Storage.setSyncedHash(item.id, syncHash, false);
- }
- Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
- Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_IN_SYNC);
- Zotero.DB.commitTransaction();
- Zotero.Sync.Storage.EventManager.changesMade();
- request.finish();
- return;
- }
- }
-
- var destFile = Zotero.getTempDirectory();
- if (info.compressed) {
- destFile.append(item.key + '.zip.tmp');
- }
- else {
- destFile.append(item.key + '.tmp');
+ var file = item.getFile();
+ // Skip download if local file exists and matches mod time
+ if (file && file.exists()) {
+ if (syncModTime == file.lastModifiedTime) {
+ Zotero.debug("File mod time matches remote file -- skipping download");
+
+ Zotero.DB.beginTransaction();
+ var syncState = Zotero.Sync.Storage.getSyncState(item.id);
+ //var updateItem = syncState != 1;
+ var updateItem = false;
+ Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
+ Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_IN_SYNC);
+ Zotero.DB.commitTransaction();
+ Zotero.Sync.Storage.EventManager.changesMade();
+ request.finish();
+ return;
}
-
- if (destFile.exists()) {
- try {
- destFile.remove(false);
- }
- catch (e) {
- Zotero.File.checkFileAccessError(e, destFile, 'delete');
+ // If not compressed, check hash, in case only timestamp changed
+ else if (!info.compressed && item.attachmentHash == syncHash) {
+ Zotero.debug("File hash matches remote file -- skipping download");
+
+ Zotero.DB.beginTransaction();
+ var syncState = Zotero.Sync.Storage.getSyncState(item.id);
+ //var updateItem = syncState != 1;
+ var updateItem = false;
+ if (!info.compressed) {
+ Zotero.Sync.Storage.setSyncedHash(item.id, syncHash, false);
}
+ Zotero.Sync.Storage.setSyncedModificationTime(item.id, syncModTime, updateItem);
+ Zotero.Sync.Storage.setSyncState(item.id, Zotero.Sync.Storage.SYNC_STATE_IN_SYNC);
+ Zotero.DB.commitTransaction();
+ Zotero.Sync.Storage.EventManager.changesMade();
+ request.finish();
+ return;
}
-
- // saveURI() below appears not to create empty files for Content-Length: 0,
- // so we create one here just in case
+ }
+
+ var destFile = Zotero.getTempDirectory();
+ if (info.compressed) {
+ destFile.append(item.key + '.zip.tmp');
+ }
+ else {
+ destFile.append(item.key + '.tmp');
+ }
+
+ if (destFile.exists()) {
try {
- destFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
+ destFile.remove(false);
}
catch (e) {
- Zotero.File.checkFileAccessError(e, destFile, 'create');
- }
-
- var listener = new Zotero.Sync.Storage.StreamListener(
- {
- onStart: function (request, data) {
- if (data.request.isFinished()) {
- Zotero.debug("Download request " + data.request.name
- + " stopped before download started -- closing channel");
- request.cancel(0x804b0002); // NS_BINDING_ABORTED
- return;
- }
- },
- onProgress: function (a, b, c) {
- request.onProgress(a, b, c)
- },
- onStop: function (request, status, response, data) {
- if (status != 200) {
- var msg = "Unexpected status code " + status
- + " for request " + data.request.name
- + " in Zotero.Sync.Storage.Module.ZFS.downloadFile()";
- Zotero.debug(msg, 1);
- Components.utils.reportError(msg);
- Zotero.Sync.Storage.EventManager.error(Zotero.Sync.Storage.defaultError);
- }
-
- // Don't try to process if the request has been cancelled
- if (data.request.isFinished()) {
- Zotero.debug("Download request " + data.request.name
- + " is no longer running after file download", 2);
- return;
- }
-
- Zotero.debug("Finished download of " + destFile.path);
-
- try {
- Zotero.Sync.Storage.processDownload(data);
- data.request.finish();
- }
- catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
- }
- },
- request: request,
- item: item,
- compressed: info.compressed,
- syncModTime: syncModTime,
- syncHash: syncHash
- }
- );
-
- var uri = getItemURI(item);
-
- // Don't display password in console
- var disp = uri.clone();
- if (disp.password) {
- disp.password = "********";
+ Zotero.File.checkFileAccessError(e, destFile, 'delete');
}
- Zotero.debug('Saving ' + disp.spec + ' with saveURI()');
- const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
- var wbp = Components
- .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
- .createInstance(nsIWBP);
- wbp.persistFlags = nsIWBP.PERSIST_FLAGS_BYPASS_CACHE;
- wbp.progressListener = listener;
- wbp.saveURI(uri, null, null, null, null, destFile);
+ }
+
+ // saveURI() below appears not to create empty files for Content-Length: 0,
+ // so we create one here just in case
+ try {
+ destFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0644);
}
catch (e) {
- Zotero.Sync.Storage.EventManager.error(e);
+ Zotero.File.checkFileAccessError(e, destFile, 'create');
}
- });
- },
-
-
- uploadFile: function (request) {
- var item = Zotero.Sync.Storage.getItemFromRequestName(request.name);
- if (Zotero.Attachments.getNumFiles(item) > 1) {
- Zotero.Sync.Storage.createUploadFile(request, function (data) { processUploadFile(data); });
+
+ var listener = new Zotero.Sync.Storage.StreamListener(
+ {
+ onStart: function (request, data) {
+ if (data.request.isFinished()) {
+ Zotero.debug("Download request " + data.request.name
+ + " stopped before download started -- closing channel");
+ request.cancel(0x804b0002); // NS_BINDING_ABORTED
+ return;
+ }
+ },
+ onProgress: function (a, b, c) {
+ request.onProgress(a, b, c)
+ },
+ onStop: function (request, status, response, data) {
+ if (status != 200) {
+ var msg = "Unexpected status code " + status
+ + " for request " + data.request.name
+ + " in Zotero.Sync.Storage.ZFS.downloadFile()";
+ Zotero.debug(msg, 1);
+ Components.utils.reportError(msg);
+ Zotero.Sync.Storage.EventManager.error(Zotero.Sync.Storage.defaultError);
+ }
+
+ // Don't try to process if the request has been cancelled
+ if (data.request.isFinished()) {
+ Zotero.debug("Download request " + data.request.name
+ + " is no longer running after file download", 2);
+ return;
+ }
+
+ Zotero.debug("Finished download of " + destFile.path);
+
+ try {
+ Zotero.Sync.Storage.processDownload(data);
+ data.request.finish();
+ }
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
+ }
+ },
+ request: request,
+ item: item,
+ compressed: info.compressed,
+ syncModTime: syncModTime,
+ syncHash: syncHash
+ }
+ );
+
+ var uri = getItemURI(item);
+
+ // Don't display password in console
+ var disp = uri.clone();
+ if (disp.password) {
+ disp.password = "********";
+ }
+ Zotero.debug('Saving ' + disp.spec + ' with saveURI()');
+ const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
+ var wbp = Components
+ .classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+ .createInstance(nsIWBP);
+ wbp.persistFlags = nsIWBP.PERSIST_FLAGS_BYPASS_CACHE;
+ wbp.progressListener = listener;
+ wbp.saveURI(uri, null, null, null, null, destFile);
}
- else {
- processUploadFile({ request: request });
+ catch (e) {
+ Zotero.Sync.Storage.EventManager.error(e);
}
- },
-
-
- getLastSyncTime: function (callback) {
- var uri = this.userURI;
- var successFileURI = uri.clone();
- successFileURI.spec += "laststoragesync?auth=1";
-
- // Cache the credentials at the root
- var self = this;
- this.cacheCredentials(function () {
- Zotero.HTTP.doGet(successFileURI, function (req) {
- if (req.responseText) {
- Zotero.debug(req.responseText);
- }
- Zotero.debug(req.status);
-
- if (req.status == 401 || req.status == 403) {
- Zotero.debug("Clearing ZFS authentication credentials", 2);
- _cachedCredentials = false;
- }
-
- if (req.status != 200 && req.status != 404) {
- Zotero.Sync.Storage.EventManager.error(
- "Unexpected status code " + req.status + " getting "
- + "last file sync time"
- );
- }
-
- if (req.status == 200) {
- var ts = req.responseText;
- var date = new Date(ts * 1000);
- Zotero.debug("Last successful storage sync was " + date);
- _lastSyncTime = ts;
- }
- else {
- var ts = null;
- _lastSyncTime = null;
- }
- callback(ts);
- });
- });
- },
-
+ });
+ };
+
+
+ obj._uploadFile = function (request) {
+ var item = Zotero.Sync.Storage.getItemFromRequestName(request.name);
+ if (Zotero.Attachments.getNumFiles(item) > 1) {
+ Zotero.Sync.Storage.createUploadFile(request, function (data) { processUploadFile(data); });
+ }
+ else {
+ processUploadFile({ request: request });
+ }
+ };
+
+
+ obj._getLastSyncTime = function (callback) {
+ var uri = this.userURI;
+ var successFileURI = uri.clone();
+ successFileURI.spec += "laststoragesync?auth=1";
- setLastSyncTime: function (callback, useLastSyncTime) {
- if (useLastSyncTime) {
- if (!_lastSyncTime) {
- if (callback) {
- callback();
- }
- return;
+ // Cache the credentials at the root
+ var self = this;
+ this._cacheCredentials(function () {
+ Zotero.HTTP.doGet(successFileURI, function (req) {
+ if (req.responseText) {
+ Zotero.debug(req.responseText);
}
+ Zotero.debug(req.status);
- var sql = "REPLACE INTO version VALUES ('storage_zfs', ?)";
- Zotero.DB.query(sql, { int: _lastSyncTime });
+ if (req.status == 401 || req.status == 403) {
+ Zotero.debug("Clearing ZFS authentication credentials", 2);
+ _cachedCredentials = false;
+ }
- Zotero.debug("Clearing ZFS authentication credentials", 2);
- _lastSyncTime = null;
- _cachedCredentials = false;
+ if (req.status != 200 && req.status != 404) {
+ Zotero.Sync.Storage.EventManager.error(
+ "Unexpected status code " + req.status + " getting "
+ + "last file sync time"
+ );
+ }
+ if (req.status == 200) {
+ var ts = req.responseText;
+ var date = new Date(ts * 1000);
+ Zotero.debug("Last successful storage sync was " + date);
+ _lastSyncTime = ts;
+ }
+ else {
+ var ts = null;
+ _lastSyncTime = null;
+ }
+ callback(ts);
+ });
+ });
+ };
+
+
+ obj._setLastSyncTime = function (callback, useLastSyncTime) {
+ if (useLastSyncTime) {
+ if (!_lastSyncTime) {
if (callback) {
callback();
}
-
return;
}
+
+ var sql = "REPLACE INTO version VALUES ('storage_zfs', ?)";
+ Zotero.DB.query(sql, { int: _lastSyncTime });
+
+ Zotero.debug("Clearing ZFS authentication credentials", 2);
_lastSyncTime = null;
+ _cachedCredentials = false;
- var uri = this.userURI;
- var successFileURI = uri.clone();
- successFileURI.spec += "laststoragesync?auth=1";
+ if (callback) {
+ callback();
+ }
- Zotero.HTTP.doPost(successFileURI, "", function (req) {
- Zotero.debug(req.responseText);
- Zotero.debug(req.status);
-
- if (req.status != 200) {
- var msg = "Unexpected status code " + req.status + " setting last file sync time";
- Zotero.debug(msg, 1);
- Components.utils.reportError(msg);
- Zotero.Sync.Storage.EventManager.error(Zotero.Sync.Storage.defaultError);
- }
-
- var ts = req.responseText;
-
- var sql = "REPLACE INTO version VALUES ('storage_zfs', ?)";
- Zotero.DB.query(sql, { int: ts });
-
- Zotero.debug("Clearing ZFS authentication credentials", 2);
- _cachedCredentials = false;
-
- if (callback) {
- callback();
- }
- });
- },
+ return;
+ }
+ _lastSyncTime = null;
+ var uri = this.userURI;
+ var successFileURI = uri.clone();
+ successFileURI.spec += "laststoragesync?auth=1";
- cacheCredentials: function (callback) {
- if (_cachedCredentials) {
- Zotero.debug("Credentials are already cached");
- setTimeout(function () {
- callback();
- }, 0);
- return false;
+ Zotero.HTTP.doPost(successFileURI, "", function (req) {
+ Zotero.debug(req.responseText);
+ Zotero.debug(req.status);
+
+ if (req.status != 200) {
+ var msg = "Unexpected status code " + req.status + " setting last file sync time";
+ Zotero.debug(msg, 1);
+ Components.utils.reportError(msg);
+ Zotero.Sync.Storage.EventManager.error(Zotero.Sync.Storage.defaultError);
}
- var uri = this.rootURI;
- // TODO: move to root uri
- uri.spec += "?auth=1";
- Zotero.HTTP.doGet(uri, function (req) {
- if (req.status == 401) {
- // TODO: localize
- var msg = "File sync login failed\n\nCheck your username and password in the Sync pane of the Zotero preferences.";
- Zotero.Sync.Storage.EventManager.error(msg);
- }
- else if (req.status != 200) {
- var msg = "Unexpected status code " + req.status + " caching "
- + "authentication credentials in Zotero.Sync.Storage.Module.ZFS.cacheCredentials()";
- Zotero.debug(msg, 1);
- Components.utils.reportError(msg);
- Zotero.Sync.Storage.EventManager.error(Zotero.Sync.Storage.defaultErrorRestart);
- }
- Zotero.debug("Credentials are cached");
- _cachedCredentials = true;
+ var ts = req.responseText;
+
+ var sql = "REPLACE INTO version VALUES ('storage_zfs', ?)";
+ Zotero.DB.query(sql, { int: ts });
+
+ Zotero.debug("Clearing ZFS authentication credentials", 2);
+ _cachedCredentials = false;
+
+ if (callback) {
callback();
- });
- return true;
- },
+ }
+ });
+ };
+
+
+ obj._cacheCredentials = function (callback) {
+ if (_cachedCredentials) {
+ Zotero.debug("Credentials are already cached");
+ setTimeout(function () {
+ callback();
+ }, 0);
+ return false;
+ }
+ var uri = this.rootURI;
+ // TODO: move to root uri
+ uri.spec += "?auth=1";
+ Zotero.HTTP.doGet(uri, function (req) {
+ if (req.status == 401) {
+ // TODO: localize
+ var msg = "File sync login failed\n\nCheck your username and password in the Sync pane of the Zotero preferences.";
+ Zotero.Sync.Storage.EventManager.error(msg);
+ }
+ else if (req.status != 200) {
+ var msg = "Unexpected status code " + req.status + " caching "
+ + "authentication credentials in Zotero.Sync.Storage.ZFS.cacheCredentials()";
+ Zotero.debug(msg, 1);
+ Components.utils.reportError(msg);
+ Zotero.Sync.Storage.EventManager.error(Zotero.Sync.Storage.defaultErrorRestart);
+ }
+ Zotero.debug("Credentials are cached");
+ _cachedCredentials = true;
+ callback();
+ });
+ return true;
+ };
+
+
+ /**
+ * Remove all synced files from the server
+ */
+ obj._purgeDeletedStorageFiles = function (callback) {
+ // If we don't have a user id we've never synced and don't need to bother
+ if (!Zotero.userID) {
+ Zotero.Sync.Storage.EventManager.skip();
+ return;
+ }
- /**
- * Remove all synced files from the server
- */
- purgeDeletedStorageFiles: function (callback) {
- // If we don't have a user id we've never synced and don't need to bother
- if (!Zotero.userID) {
- Zotero.Sync.Storage.EventManager.skip();
- return;
+ var sql = "SELECT value FROM settings WHERE setting=? AND key=?";
+ var values = Zotero.DB.columnQuery(sql, ['storage', 'zfsPurge']);
+ if (!values) {
+ Zotero.Sync.Storage.EventManager.skip();
+ return;
+ }
+
+ Zotero.debug("Unlinking synced files on ZFS");
+
+ var uri = this.userURI;
+ uri.spec += "removestoragefiles?";
+ // Unused
+ for each(var value in values) {
+ switch (value) {
+ case 'user':
+ uri.spec += "user=1&";
+ break;
+
+ case 'group':
+ uri.spec += "group=1&";
+ break;
+
+ default:
+ Zotero.Sync.Storage.EventManager.error(
+ "Invalid zfsPurge value '" + value + "' in ZFS purgeDeletedStorageFiles()"
+ );
}
-
- var sql = "SELECT value FROM settings WHERE setting=? AND key=?";
- var values = Zotero.DB.columnQuery(sql, ['storage', 'zfsPurge']);
- if (!values) {
- Zotero.Sync.Storage.EventManager.skip();
- return;
+ }
+ uri.spec = uri.spec.substr(0, uri.spec.length - 1);
+
+ Zotero.HTTP.doPost(uri, "", function (xmlhttp) {
+ if (xmlhttp.status != 204) {
+ if (callback) {
+ callback(false);
+ }
+ Zotero.Sync.Storage.EventManager.error(
+ "Unexpected status code " + xmlhttp.status + " purging ZFS files"
+ );
}
- Zotero.debug("Unlinking synced files on ZFS");
+ var sql = "DELETE FROM settings WHERE setting=? AND key=?";
+ Zotero.DB.query(sql, ['storage', 'zfsPurge']);
- var uri = this.userURI;
- uri.spec += "removestoragefiles?";
- // Unused
- for each(var value in values) {
- switch (value) {
- case 'user':
- uri.spec += "user=1&";
- break;
-
- case 'group':
- uri.spec += "group=1&";
- break;
-
- default:
- Zotero.Sync.Storage.EventManager.error(
- "Invalid zfsPurge value '" + value + "' in ZFS purgeDeletedStorageFiles()"
- );
- }
+ if (callback) {
+ callback(true);
}
- uri.spec = uri.spec.substr(0, uri.spec.length - 1);
- Zotero.HTTP.doPost(uri, "", function (xmlhttp) {
- if (xmlhttp.status != 204) {
- if (callback) {
- callback(false);
- }
- Zotero.Sync.Storage.EventManager.error(
- "Unexpected status code " + xmlhttp.status + " purging ZFS files"
- );
- }
-
- var sql = "DELETE FROM settings WHERE setting=? AND key=?";
- Zotero.DB.query(sql, ['storage', 'zfsPurge']);
-
- if (callback) {
- callback(true);
- }
-
- Zotero.Sync.Storage.EventManager.success();
- });
- }
- }
+ Zotero.Sync.Storage.EventManager.success();
+ });
+ };
+
+ return obj;
}());
diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js
@@ -421,7 +421,7 @@ Zotero.Sync.EventListener = new function () {
var sql = "REPLACE INTO syncDeleteLog VALUES (?, ?, ?, ?)";
var syncStatement = Zotero.DB.getStatement(sql);
- if (isItem && Zotero.Sync.Storage.isActive('WebDAV')) {
+ if (isItem && Zotero.Sync.Storage.WebDAV.active) {
var storageEnabled = true;
var sql = "INSERT INTO storageDeleteLog VALUES (?, ?, ?)";
var storageStatement = Zotero.DB.getStatement(sql);
@@ -559,7 +559,7 @@ Zotero.Sync.Runner = new function () {
Zotero.Sync.Runner.setSyncStatus(Zotero.getString('sync.status.syncingFiles'));
var zfsSync = function (skipSyncNeeded) {
- Zotero.Sync.Storage.sync('ZFS', {
+ Zotero.Sync.Storage.ZFS.sync({
// ZFS success
onSuccess: function () {
setTimeout(function () {
@@ -593,7 +593,7 @@ Zotero.Sync.Runner = new function () {
})
};
- Zotero.Sync.Storage.sync('WebDAV', {
+ Zotero.Sync.Storage.WebDAV.sync({
// WebDAV success
onSuccess: function () {
zfsSync(true);
diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js
@@ -1801,12 +1801,12 @@ const ZOTERO_CONFIG = {
Zotero.Relations.purge();
if (!skipStoragePurge && Math.random() < 1/10) {
- Zotero.Sync.Storage.purgeDeletedStorageFiles('ZFS');
- Zotero.Sync.Storage.purgeDeletedStorageFiles('WebDAV');
+ Zotero.Sync.Storage.ZFS.purgeDeletedStorageFiles();
+ Zotero.Sync.Storage.WebDAV.purgeDeletedStorageFiles();
}
if (!skipStoragePurge) {
- Zotero.Sync.Storage.purgeOrphanedStorageFiles('WebDAV');
+ Zotero.Sync.Storage.WebDAV.purgeOrphanedStorageFiles();
}
}
diff --git a/components/zotero-service.js b/components/zotero-service.js
@@ -100,7 +100,7 @@ const xpcomFilesLocal = [
'storage/queueManager',
'storage/queue',
'storage/request',
- 'storage/module',
+ 'storage/mode',
'storage/zfs',
'storage/webdav',
'timeline',