commit 7fd299bd6416df8332eefaa98647c20a2a98db68
parent 4a90c8acdaa15417637c75d87e8c934cc9897233
Author: Simon Kornblith <simon@simonster.com>
Date: Sat, 26 Mar 2011 04:20:22 +0000
Add back old integration pipe modes for use on Linux
Diffstat:
2 files changed, 200 insertions(+), 11 deletions(-)
diff --git a/chrome/content/zotero/xpcom/integration.js b/chrome/content/zotero/xpcom/integration.js
@@ -41,7 +41,7 @@ Zotero.Integration = new function() {
var _osascriptFile;
var _inProgress = false;
var _integrationVersionsOK = null;
- var _useDeferredOpenForIntegrationPipe = false;
+ var _pipeMode = false;
var _winUser32;
this.sessions = {};
@@ -213,9 +213,9 @@ Zotero.Integration = new function() {
/**
* Listens asynchronously for data on the integration pipe and reads it when available
*
- * Used to read from the integration pipe on Fx 4
+ * Used to read from the integration pipe on Fx 4.2
*/
- var _integrationPipeListenerFx4 = {
+ var _integrationPipeListenerFx42 = {
"onStartRequest":function() {},
"onStopRequest":function() {},
@@ -256,8 +256,8 @@ Zotero.Integration = new function() {
* Initializes the nsIInputStream and nsIInputStreamPump to read from _fifoFile
*/
function _initializePipeStreamPump() {
- if(_useDeferredOpenForIntegrationPipe) {
- // Fx 4 supports deferred open; no need to use sh
+ if(_pipeMode === "deferredOpen") {
+ // Fx >4 supports deferred open; no need to use sh
var fifoStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
fifoStream.QueryInterface(Components.interfaces.nsIFileInputStream);
@@ -267,7 +267,7 @@ Zotero.Integration = new function() {
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].
createInstance(Components.interfaces.nsIInputStreamPump);
pump.init(fifoStream, -1, -1, 4096, 1, true);
- pump.asyncRead(_integrationPipeListenerFx4, null);
+ pump.asyncRead(_integrationPipeListenerFx42, null);
} else {
// Fx 3.6 doesn't support deferred open
_shProc.runAsync(_shCmd, _shCmd.length, _integrationPipeObserverFx36);
@@ -278,7 +278,29 @@ Zotero.Integration = new function() {
* Initializes the Zotero Integration Pipe
*/
function _initializeIntegrationPipe() {
- _useDeferredOpenForIntegrationPipe = false; // this will only work with Gecko 2.0.1
+ 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(Zotero.isFx4) {
+ if(verComp.compare("2.0b9pre", appInfo.platformVersion) > 0) {
+ Components.utils.reportError("Zotero word processor integration requires "+
+ "Firefox 4.0b9 or later. Please update to the latest Firefox 4.0 beta.");
+ return;
+ } else if(verComp.compare("2.2a1pre", appInfo.platformVersion) <= 0) {
+ _pipeMode = "deferredOpen";
+ } else {
+ _pipeMode = "fx4thread";
+ }
+ } else {
+ if(Zotero.isMac) {
+ _pipeMode = "subprocess";
+ } else {
+ _pipeMode = "fx36thread";
+ }
+ }
+
+ Zotero.debug("Using integration pipe mode "+_pipeMode);
// make a new pipe
var mkfifo = Components.classes["@mozilla.org/file/local;1"].
@@ -300,7 +322,7 @@ Zotero.Integration = new function() {
proc.run(true, [_fifoFile.path], 1);
if(_fifoFile.exists()) {
- if(!_useDeferredOpenForIntegrationPipe) {
+ if(_pipeMode === "subprocess") {
// no deferred open capability, so we need to use the sh/tmpfile hack
// make a tmp file
@@ -318,10 +340,104 @@ Zotero.Integration = new function() {
_shProc = Components.classes["@mozilla.org/process/util;1"].
createInstance(Components.interfaces.nsIProcess);
_shProc.init(sh);
+
+ _initializePipeStreamPump();
+ } else if(_pipeMode === "deferredOpen") {
+ _initializePipeStreamPump();
+ } else if(_pipeMode === "fx36thread") {
+ var main = Components.classes["@mozilla.org/thread-manager;1"].getService().mainThread;
+ var background = Components.classes["@mozilla.org/thread-manager;1"].getService().newThread(0);
+
+ function mainThread(agent, cmd, doc) {
+ this.agent = agent;
+ this.cmd = cmd;
+ this.document = doc;
+ }
+ mainThread.prototype.run = function() {
+ Zotero.Integration.execCommand(this.agent, this.cmd, this.document);
+ }
+
+ function fifoThread() {}
+ fifoThread.prototype.run = function() {
+ var fifoStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var line = {};
+ while(true) {
+ fifoStream.QueryInterface(Components.interfaces.nsIFileInputStream);
+ fifoStream.init(_fifoFile, -1, 0, 0);
+ fifoStream.QueryInterface(Components.interfaces.nsILineInputStream);
+ fifoStream.readLine(line);
+ fifoStream.close();
+
+ var parts = line.value.split(" ");
+ var agent = parts[0];
+ var cmd = parts[1];
+ var document = parts.length >= 3 ? line.value.substr(agent.length+cmd.length+2) : null;
+ if(agent == "Zotero" && cmd == "shutdown") return;
+ main.dispatch(new mainThread(agent, cmd, document), background.DISPATCH_NORMAL);
+ }
+ }
+
+ fifoThread.prototype.QueryInterface = mainThread.prototype.QueryInterface = function(iid) {
+ if (iid.equals(Components.interfaces.nsIRunnable) ||
+ iid.equals(Components.interfaces.nsISupports)) return this;
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ }
+
+ background.dispatch(new fifoThread(), background.DISPATCH_NORMAL);
+ } else if(_pipeMode === "fx4thread") {
+ Components.utils.import("resource://gre/modules/ctypes.jsm");
+
+ // get possible names for libc
+ if(Zotero.isMac) {
+ var possibleLibcs = ["/usr/lib/libc.dylib"];
+ } else {
+ var possibleLibcs = [
+ "libc.so.6",
+ "libc.so.6.1",
+ "libc.so"
+ ];
+ }
+
+ // try all possibilities
+ while(possibleLibcs.length) {
+ var libc = possibleLibcs.shift();
+ try {
+ var lib = ctypes.open(libc);
+ break;
+ } catch(e) {}
+ }
+
+ // throw appropriate error on failure
+ if(!lib) {
+ throw "libc could not be loaded. Please post on the Zotero Forums so we can add "+
+ "support for your operating system.";
+ }
+
+ // int mkfifo(const char *path, mode_t mode);
+ var mkfifo = lib.declare("mkfifo", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.unsigned_int);
+
+ // make pipe
+ var ret = mkfifo(_fifoFile.path, 0600);
+ if(!_fifoFile.exists()) return false;
+ lib.close();
+
+ // set up worker
+ var worker = Components.classes["@mozilla.org/threads/workerfactory;1"]
+ .createInstance(Components.interfaces.nsIWorkerFactory)
+ .newChromeWorker("chrome://zotero/content/xpcom/integration_worker.js");
+ worker.onmessage = function(event) {
+ if(event.data[0] == "Exception") {
+ throw event.data[1];
+ } else if(event.data[0] == "Debug") {
+ Zotero.debug(event.data[1]);
+ } else {
+ Zotero.Integration.execCommand(event.data[0], event.data[1], event.data[2]);
+ }
+ }
+ worker.postMessage({"path":_fifoFile.path, "libc":libc});
}
- _initializePipeStreamPump();
-
return true;
}
@@ -441,7 +557,7 @@ Zotero.Integration = new function() {
oStream.write(cmd, cmd.length);
oStream.close();
_fifoFile.remove(false);
- if(!__useDeferredOpenForIntegrationPipe) _tmpFile.remove(false);
+ if(_pipeMode === "subprocess") _tmpFile.remove(false);
}
/**
diff --git a/chrome/content/zotero/xpcom/integration_worker.js b/chrome/content/zotero/xpcom/integration_worker.js
@@ -0,0 +1,72 @@
+/*
+ ***** 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 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Zotero. If not, see <http://www.gnu.org/licenses/>.
+
+ ***** END LICENSE BLOCK *****
+*/
+
+onmessage = function(event) {
+ var path = event.data.path;
+
+ // ctypes declarations follow
+ var lib = ctypes.open(event.data.libc);
+
+ // int open(const char *path, int oflag, ...);
+ var open = lib.declare("open", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.int);
+
+ // ssize_t read(int fildes, void *buf, size_t nbyte);
+ var read = lib.declare("read", ctypes.default_abi, ctypes.ssize_t, ctypes.int,
+ ctypes.char.ptr, ctypes.size_t);
+
+ // int close(int fildes);
+ var close = lib.declare("close", ctypes.default_abi, ctypes.int, ctypes.int);
+
+ // define buffer for reading from fifo
+ const BUFFER_SIZE = 4096;
+
+ while(true) {
+ var buf = ctypes.char.array(BUFFER_SIZE)("");
+
+ // open fifo (this will block until something writes to it)
+ var fd = open(path, 0);
+
+ // read from fifo and close it
+ read(fd, buf, BUFFER_SIZE-1);
+ close(fd);
+
+ // extract message
+ var string = buf.readString();
+ var parts = string.match(/^([^ \n]*) ([^ \n]*)(?: ([^\n]*))?\n?$/);
+ if(!parts) {
+ postMessage(["Exception", "Integration Worker: Invalid input received: "+string]);
+ continue;
+ }
+ var agent = parts[1].toString();
+ var cmd = parts[2].toString();
+ var document = parts[3] ? parts[3] : null;
+ if(agent == "Zotero" && cmd == "shutdown") {
+ postMessage(["Debug", "Integration Worker: Shutting down"]);
+ lib.close();
+ return;
+ }
+ postMessage([agent, cmd, document]);
+ }
+};
+\ No newline at end of file