diff --git a/chrome/content/zotero/xpcom/dataDirectory.js b/chrome/content/zotero/xpcom/dataDirectory.js index 01651324f8..013e10a00e 100644 --- a/chrome/content/zotero/xpcom/dataDirectory.js +++ b/chrome/content/zotero/xpcom/dataDirectory.js @@ -909,39 +909,6 @@ Zotero.DataDirectory = { return false; } - // Check for an existing pipe from other running versions of Zotero pointing at the same data - // directory, and skip migration if found - try { - let foundPipe = yield Zotero.IPC.pipeExists(); - if (foundPipe) { - Zotero.debug("Found existing pipe -- skipping migration"); - - if (!automatic) { - let ps = Services.prompt; - let buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING) - + (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING); - let index = ps.confirmEx(null, - Zotero.getString('dataDir.migration.failure.title'), - Zotero.getString('dataDir.migration.failure.full.firefoxOpen'), - buttonFlags, - Zotero.getString('general.tryAgain'), - Zotero.getString('general.tryLater'), - null, null, {} - ); - - if (index == 0) { - return this.checkForMigration(newDir, newDir); - } - } - - return false; - } - } - catch (e) { - Zotero.logError("Error checking for pipe -- skipping migration:\n\n" + e); - return false; - } - // If there are other profiles pointing to the old directory, make sure we can edit the prefs.js // file before doing anything, or else we risk orphaning a 4.0 installation try { @@ -1043,10 +1010,6 @@ Zotero.DataDirectory = { // Set data directory again Zotero.debug("Using new data directory " + newDir); this._cache(newDir); - // Tell Zotero for Firefox in connector mode to reload and find the new data directory - if (Zotero.isStandalone) { - Zotero.IPC.broadcast('reinit'); - } // At least the database was copied, but other things failed if (errors.length) { diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js index 4cd06aeba2..76a79a3b07 100644 --- a/chrome/content/zotero/xpcom/integration.js +++ b/chrome/content/zotero/xpcom/integration.js @@ -128,7 +128,6 @@ Zotero.Integration = new function() { this.deletePipe = function(pipe) { try { if(pipe.exists()) { - Zotero.IPC.safePipeWrite(pipe, "Zotero shutdown\n"); pipe.remove(false); } return true; diff --git a/chrome/content/zotero/xpcom/ipc.js b/chrome/content/zotero/xpcom/ipc.js index 6dba6bdf33..cdbeae9de8 100755 --- a/chrome/content/zotero/xpcom/ipc.js +++ b/chrome/content/zotero/xpcom/ipc.js @@ -27,79 +27,6 @@ Zotero.IPC = new function() { var _libc, _libcPath, _instancePipe, _user32, open, write, close; /** - * Initialize pipe for communication with connector - */ - this.init = function() { - if(!Zotero.isWin) { // no pipe support on Fx 3.6 - _instancePipe = _getPipeDirectory(); - if(!_instancePipe.exists()) { - _instancePipe.create(Ci.nsIFile.DIRECTORY_TYPE, 0o700); - } - _instancePipe.append(Zotero.instanceID); - - Zotero.IPC.Pipe.initPipeListener(_instancePipe, this.parsePipeInput); - } - } - - /** - * Parses input received via instance pipe - */ - this.parsePipeInput = function(msgs) { - for (let msg of msgs.split("\n")) { - if(!msg) continue; - Zotero.debug('IPC: Received "'+msg+'"'); - - /* - * The below messages coordinate switching Zotero for Firefox from extension mode to - * connector mode without restarting after Zotero Standalone has been launched. The - * dance typically proceeds as follows: - * - * 1. SA sends a releaseLock message to Z4Fx that tells it to release its lock. - * 2. Z4Fx releases its lock and sends a lockReleased message to SA. - * 3. Z4Fx restarts in connector mode. Once it's ready for an IPC command, it sends - * a checkInitComplete message to SA. - * 4. Once SA finishes initializing, or immediately after a checkInitComplete message - * has been received if it is already initialized, SA sends an initComplete message - * to Z4Fx. - */ - if(msg.substr(0, 11) === "releaseLock") { - // Standalone sends this to the Firefox extension to tell the Firefox extension to - // release its lock on the Zotero database - if(!Zotero.isConnector && (msg.length === 11 || - msg.substr(12) === Zotero.DataDirectory.getDatabase())) { - switchConnectorMode(true); - } - } else if(msg === "lockReleased") { - // The Firefox extension sends this to Standalone to let Standalone know that it has - // released its lock - Zotero.onDBLockReleased(); - } else if(msg === "checkInitComplete") { - // The Firefox extension sends this to Standalone to tell Standalone to send an - // initComplete message when it is fully initialized - if(Zotero.initialized) { - Zotero.IPC.broadcast("initComplete"); - } else { - var observerService = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); - var _loadObserver = function() { - Zotero.IPC.broadcast("initComplete"); - observerService.removeObserver(_loadObserver, "zotero-loaded"); - }; - observerService.addObserver(_loadObserver, "zotero-loaded", false); - } - } else if(msg === "initComplete") { - // Standalone sends this to the Firefox extension to let the Firefox extension - // know that Standalone has fully initialized and it should pull the list of - // translators - Zotero.initComplete(); - } - else if (msg == "reinit") { - if (Zotero.isConnector) { - reinit(false, true); - } - } - } - } /** * Writes safely to a file, avoiding blocking. @@ -135,165 +62,6 @@ Zotero.IPC = new function() { return true; } - /** - * Broadcast a message to all other Zotero instances - */ - this.broadcast = function(msg) { - if(Zotero.isWin) { // communicate via WM_COPYDATA method - Components.utils.import("resource://gre/modules/ctypes.jsm"); - - // communicate via message window - var user32 = ctypes.open("user32.dll"); - - /* http://msdn.microsoft.com/en-us/library/ms633499%28v=vs.85%29.aspx - * HWND WINAPI FindWindow( - * __in_opt LPCTSTR lpClassName, - * __in_opt LPCTSTR lpWindowName - * ); - */ - var FindWindow = user32.declare("FindWindowW", ctypes.winapi_abi, ctypes.int32_t, - ctypes.jschar.ptr, ctypes.jschar.ptr); - - /* http://msdn.microsoft.com/en-us/library/ms633539%28v=vs.85%29.aspx - * BOOL WINAPI SetForegroundWindow( - * __in HWND hWnd - * ); - */ - var SetForegroundWindow = user32.declare("SetForegroundWindow", ctypes.winapi_abi, - ctypes.bool, ctypes.int32_t); - - /* - * LRESULT WINAPI SendMessage( - * __in HWND hWnd, - * __in UINT Msg, - * __in WPARAM wParam, - * __in LPARAM lParam - * ); - */ - var SendMessage = user32.declare("SendMessageW", ctypes.winapi_abi, ctypes.uintptr_t, - ctypes.int32_t, ctypes.unsigned_int, ctypes.voidptr_t, ctypes.voidptr_t); - - /* http://msdn.microsoft.com/en-us/library/ms649010%28v=vs.85%29.aspx - * typedef struct tagCOPYDATASTRUCT { - * ULONG_PTR dwData; - * DWORD cbData; - * PVOID lpData; - * } COPYDATASTRUCT, *PCOPYDATASTRUCT; - */ - var COPYDATASTRUCT = ctypes.StructType("COPYDATASTRUCT", [ - {"dwData":ctypes.voidptr_t}, - {"cbData":ctypes.uint32_t}, - {"lpData":ctypes.voidptr_t} - ]); - - // Aurora/Nightly are always named "Firefox" in - // application.ini - const appNames = ["Firefox", "Zotero"]; - - // Different from Zotero.appName; this corresponds to the - // name in application.ini - const myAppName = Services.appinfo.name; - - for (let appName of appNames) { - // don't send messages to ourself - if(appName === myAppName) continue; - - var thWnd = FindWindow(appName+"MessageWindow", null); - if(thWnd) { - Zotero.debug('IPC: Broadcasting "'+msg+'" to window "'+appName+'MessageWindow"'); - - // allocate message - var data = ctypes.char.array()('firefox.exe -silent -ZoteroIPC "'+msg.replace('"', '""', "g")+'"\x00C:\\'); - var dataSize = data.length*data.constructor.size; - - // create new COPYDATASTRUCT - var cds = new COPYDATASTRUCT(); - cds.dwData = null; - cds.cbData = dataSize; - cds.lpData = data.address(); - - // send COPYDATASTRUCT - var success = SendMessage(thWnd, 0x004A /** WM_COPYDATA **/, null, cds.address()); - - user32.close(); - return !!success; - } - } - - user32.close(); - return false; - } else { // communicate via pipes - // look for other Zotero instances - var pipes = []; - var pipeDir = _getPipeDirectory(); - if(pipeDir.exists()) { - var dirEntries = pipeDir.directoryEntries; - while (dirEntries.hasMoreElements()) { - var pipe = dirEntries.getNext().QueryInterface(Ci.nsIFile); - if(pipe.leafName[0] !== "." && (!_instancePipe || !pipe.equals(_instancePipe))) { - pipes.push(pipe); - } - } - } - - if(!pipes.length) return false; - var success = false; - for (let pipe of pipes) { - Zotero.debug('IPC: Trying to broadcast "'+msg+'" to instance '+pipe.leafName); - - var defunct = false; - - if(pipe.isFile()) { - // not actually a pipe - if(pipe.isDirectory()) { - // not a file, so definitely defunct - defunct = true; - } else { - // check to see whether the size exceeds a certain threshold that we find - // reasonable for the queue, and if not, delete the pipe, because it's - // probably just a file that wasn't deleted on shutdown and is now - // accumulating vast amounts of data - defunct = pipe.fileSize > 1024; - } - } - - if(!defunct) { - // Try to write to the pipe for 100 ms - var time = Date.now(), timeout = time+100, wroteToPipe; - do { - wroteToPipe = Zotero.IPC.safePipeWrite(pipe, msg+"\n"); - } while(Date.now() < timeout && !wroteToPipe); - if (wroteToPipe) Zotero.debug('IPC: Pipe took '+(Date.now()-time)+' ms to become available'); - success = success || wroteToPipe; - defunct = !wroteToPipe; - } - - if(defunct) { - Zotero.debug('IPC: Removing defunct pipe '+pipe.leafName); - try { - pipe.remove(true); - } catch(e) {}; - } - } - - return success; - } - } - - /** - * Get directory containing Zotero pipes - */ - function _getPipeDirectory() { - var dir = Zotero.File.pathToFile(Zotero.DataDirectory.dir); - dir.append("pipes"); - return dir; - } - - this.pipeExists = Zotero.Promise.coroutine(function* () { - var dir = _getPipeDirectory().path; - return (yield OS.File.exists(dir)) && !(yield Zotero.File.directoryIsEmpty(dir)); - }); - /** * Gets the path to libc as a string */ @@ -359,19 +127,8 @@ Zotero.IPC.Pipe = new function() { this.initPipeListener = function(file, callback) { Zotero.debug("IPC: Initializing pipe at "+file.path); - // determine type of pipe - if(!_pipeClass) { - var verComp = Components.classes["@mozilla.org/xpcom/version-comparator;1"] - .getService(Components.interfaces.nsIVersionComparator); - var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]. - getService(Components.interfaces.nsIXULAppInfo); - if(verComp.compare("2.2a1pre", appInfo.platformVersion) <= 0) { // Gecko 5 - _pipeClass = Zotero.IPC.Pipe.DeferredOpen; - } - } - // make new pipe - new _pipeClass(file, callback); + new Zotero.IPC.Pipe.DeferredOpen(file, callback); } /** @@ -395,7 +152,7 @@ Zotero.IPC.Pipe = new function() { * Adds a shutdown listener for a pipe that writes "Zotero shutdown\n" to the pipe and then * deletes it */ - this.writeShutdownMessage = function(pipe, file) { + this.remove = function(pipe, file) { // Make sure pipe actually exists if(!file.exists()) { Zotero.debug("IPC: Not closing pipe "+file.path+": already deleted"); @@ -425,7 +182,7 @@ Zotero.IPC.Pipe.DeferredOpen = function(file, callback) { this._initPump(); // add shutdown listener - Zotero.addShutdownListener(Zotero.IPC.Pipe.writeShutdownMessage.bind(null, this, file)); + Zotero.addShutdownListener(Zotero.IPC.Pipe.remove.bind(null, this, file)); } Zotero.IPC.Pipe.DeferredOpen.prototype = { diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js index 1986a6a833..dd2ee06a52 100644 --- a/chrome/content/zotero/xpcom/zotero.js +++ b/chrome/content/zotero/xpcom/zotero.js @@ -385,16 +385,6 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js"); var _shutdownObserver = {observe:function() { Zotero.shutdown().done() }}; Services.obs.addObserver(_shutdownObserver, "quit-application", false); - try { - Zotero.IPC.init(); - } - catch (e) { - if (_checkDataDirAccessError(e)) { - return false; - } - throw (e); - } - // Get startup errors try { let messages = Services.console.getMessageArray(); @@ -783,11 +773,6 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js"); let dbfile = Zotero.DataDirectory.getDatabase(); - // Tell any other Zotero instances to release their lock, - // in case we lost the lock on the database (how?) and it's - // now open in two places at once - Zotero.IPC.broadcast("releaseLock " + dbfile); - // Test write access on Zotero data directory if (!Zotero.File.pathToFile(OS.Path.dirname(dbfile)).isWritable()) { var msg = 'Cannot write to ' + OS.Path.dirname(dbfile) + '/'; @@ -906,11 +891,6 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js"); if (Zotero.DB) { // close DB yield Zotero.DB.closeDatabase(true) - - if (!Zotero.restarting) { - // broadcast that DB lock has been released - Zotero.IPC.broadcast("lockReleased"); - } } } catch(e) { Zotero.logError(e); diff --git a/components/zotero-service.js b/components/zotero-service.js index d334831a91..f09160fb99 100644 --- a/components/zotero-service.js +++ b/components/zotero-service.js @@ -531,17 +531,7 @@ ZoteroCommandLineHandler.prototype = { zContext.Zotero.Integration.execCommand(agent, command, docId, templateVersion); } - - // handler for Windows IPC commands - var ipcParam = cmdLine.handleFlagWithParam("ZoteroIPC", false); - if(ipcParam) { - // Don't open a new window - cmdLine.preventDefault = true; - if (!zContext) new ZoteroService(); - let Zotero = zContext.Zotero; - Zotero.setTimeout(() => Zotero.IPC.parsePipeInput(ipcParam), 0); - } - + if(isStandalone()) { var fileToOpen; // Special handler for "zotero" URIs at the command line to prevent them from opening a new window diff --git a/test/tests/dataDirectoryTest.js b/test/tests/dataDirectoryTest.js index a521f8b269..9fa1ce0aaf 100644 --- a/test/tests/dataDirectoryTest.js +++ b/test/tests/dataDirectoryTest.js @@ -37,8 +37,6 @@ describe("Zotero.DataDirectory", function () { newMigrationMarker = OS.Path.join(newDir, Zotero.DataDirectory.MIGRATION_MARKER); stubs.canMigrate = sinon.stub(Zotero.DataDirectory, "canMigrate").returns(true); - // A pipe always exists during tests, since Zotero is running - stubs.pipeExists = sinon.stub(Zotero.IPC, "pipeExists").returns(Zotero.Promise.resolve(false)); stubs.setDataDir = sinon.stub(Zotero.DataDirectory, "set"); stubs.isNewDirOnDifferentDrive = sinon.stub(Zotero.DataDirectory, 'isNewDirOnDifferentDrive').resolves(true); });