From 79b1fe30dcb36b810fae27bbae4e1197688bae52 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 20 Jan 2012 15:23:06 -0500 Subject: [PATCH] Workaround for broken file/URL launching in Standalone on Linux Falls back to /usr/bin/xdg-open by default, configurable via extensions.zotero.fallbackLauncher.unix (or .windows, though that should be much rarer). Also used for file revealing. If xdg-open fails, files launch via the external helper app dialog and URLs just don't work. --- chrome/content/zotero/zoteroPane.js | 156 +++++++++++++++++++++------- defaults/preferences/zotero.js | 6 +- 2 files changed, 121 insertions(+), 41 deletions(-) diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js index 70a6ec588c..ddf42f604c 100644 --- a/chrome/content/zotero/zoteroPane.js +++ b/chrome/content/zotero/zoteroPane.js @@ -2682,14 +2682,7 @@ var ZoteroPane = new function() if (Zotero.isStandalone) { if(uri.match(/^https?/)) { - var io = Components.classes['@mozilla.org/network/io-service;1'] - .getService(Components.interfaces.nsIIOService); - var uri = io.newURI(uri, null, null); - var handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1'] - .getService(Components.interfaces.nsIExternalProtocolService) - .getProtocolHandlerInfo('http'); - handler.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault; - handler.launchWithURI(uri, null); + this.launchURL(uri); } else { ZoteroStandalone.openInViewer(uri); } @@ -3408,22 +3401,7 @@ var ZoteroPane = new function() this.loadURI(url, event); } else { - // Some platforms don't have nsILocalFile.launch, so we just - // let the Firefox external helper app window handle it - try { - file.launch(); - } - catch (e) { - Zotero.debug("launch() not supported -- passing file to loadUrl()"); - - var uri = Components.classes["@mozilla.org/network/standard-url;1"]. - createInstance(Components.interfaces.nsIURI); - uri.spec = attachment.getLocalFileURL(); - - var nsIEPS = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]. - getService(Components.interfaces.nsIExternalProtocolService); - nsIEPS.loadUrl(uri); - } + this.launchFile(file); } } else { @@ -3433,6 +3411,116 @@ var ZoteroPane = new function() } + /** + * Launch a file, the best way we can + */ + this.launchFile = function (file) { + try { + file.launch(); + } + catch (e) { + Zotero.debug("launch() not supported -- trying fallback executable"); + + try { + if (Zotero.isWin) { + var pref = "fallbackLauncher.windows"; + } + else { + var pref = "fallbackLauncher.unix"; + } + var path = Zotero.Prefs.get(pref); + + var exec = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + exec.initWithPath(path); + if (!exec.exists()) { + throw (path + " does not exist"); + } + + var proc = Components.classes["@mozilla.org/process/util;1"] + .createInstance(Components.interfaces.nsIProcess); + proc.init(exec); + + var args = [file.path]; + if (!Zotero.isFx36) { + proc.runw(true, args, args.length); + } + else { + proc.run(true, args, args.length); + } + } + catch (e) { + Zotero.debug(e); + Zotero.debug("Launching via executable failed -- passing to loadUrl()"); + + // If nsILocalFile.launch() isn't available and the fallback + // executable doesn't exist, we just let the Firefox external + // helper app window handle it + var nsIFPH = Components.classes["@mozilla.org/network/protocol;1?name=file"] + .getService(Components.interfaces.nsIFileProtocolHandler); + var uri = nsIFPH.newFileURI(file); + + var nsIEPS = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]. + getService(Components.interfaces.nsIExternalProtocolService); + nsIEPS.loadUrl(uri); + } + } + } + + + /** + * Launch an HTTP URL externally, the best way we can + * + * Used only by Standalone + */ + this.launchURL = function (url) { + if (!url.match(/^https?/)) { + throw new Error("launchURL() requires an HTTP(S) URL"); + } + + try { + var io = Components.classes['@mozilla.org/network/io-service;1'] + .getService(Components.interfaces.nsIIOService); + var uri = io.newURI(url, null, null); + var handler = Components.classes['@mozilla.org/uriloader/external-protocol-service;1'] + .getService(Components.interfaces.nsIExternalProtocolService) + .getProtocolHandlerInfo('http'); + handler.preferredAction = Components.interfaces.nsIHandlerInfo.useSystemDefault; + handler.launchWithURI(uri, null); + } + catch (e) { + Zotero.debug("launchWithURI() not supported -- trying fallback executable"); + + if (Zotero.isWin) { + var pref = "fallbackLauncher.windows"; + } + else { + var pref = "fallbackLauncher.unix"; + } + var path = Zotero.Prefs.get(pref); + + var exec = Components.classes["@mozilla.org/file/local;1"] + .createInstance(Components.interfaces.nsILocalFile); + exec.initWithPath(path); + if (!exec.exists()) { + throw ("Fallback executable not found -- check extensions.zotero." + pref + " in about:config"); + } + + var proc = Components.classes["@mozilla.org/process/util;1"] + .createInstance(Components.interfaces.nsIProcess); + proc.init(exec); + + var args = [url]; + if (!Zotero.isFx36) { + proc.runw(true, args, args.length); + } + else { + proc.run(true, args, args.length); + } + } + } + + function viewSelectedAttachment(event, noLocateOnMissing) { if (this.itemsView && this.itemsView.selection.count == 1) { @@ -3445,27 +3533,15 @@ var ZoteroPane = new function() var attachment = Zotero.Items.get(itemID) if (attachment.attachmentLinkMode != Zotero.Attachments.LINK_MODE_LINKED_URL) { var file = attachment.getFile(); - if (file){ + if (file) { try { file.reveal(); } catch (e) { // On platforms that don't support nsILocalFile.reveal() (e.g. Linux), - // "double-click" the parent directory - try { - var parent = file.parent.QueryInterface(Components.interfaces.nsILocalFile); - parent.launch(); - } - // If launch also fails, try the OS handler - catch (e) { - var uri = Components.classes["@mozilla.org/network/io-service;1"]. - getService(Components.interfaces.nsIIOService). - newFileURI(parent); - var protocolService = - Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]. - getService(Components.interfaces.nsIExternalProtocolService); - protocolService.loadUrl(uri); - } + // launch the parent directory + var parent = file.parent.QueryInterface(Components.interfaces.nsILocalFile); + this.launchFile(parent); } } else { diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index 523c1ae587..9efcf87b91 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -161,4 +161,8 @@ pref("extensions.zotero.ingester.allowedSites", ""); // Connector pref("extensions.zotero.connector.repo.lastCheck.localTime", 0); -pref("extensions.zotero.connector.repo.lastCheck.repoTime", 0); \ No newline at end of file +pref("extensions.zotero.connector.repo.lastCheck.repoTime", 0); + +// File/URL opening executable if launch() fails +pref("extensions.zotero.fallbackLauncher.unix", "/usr/bin/xdg-open"); +pref("extensions.zotero.fallbackLauncher.windows", ""); \ No newline at end of file