www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

zotero-service.js (20330B)


      1 /*
      2     ***** BEGIN LICENSE BLOCK *****
      3     
      4     Copyright © 2009 Center for History and New Media
      5                      George Mason University, Fairfax, Virginia, USA
      6                      http://zotero.org
      7     
      8     This file is part of Zotero.
      9     
     10     Zotero is free software: you can redistribute it and/or modify
     11     it under the terms of the GNU Affero General Public License as published by
     12     the Free Software Foundation, either version 3 of the License, or
     13     (at your option) any later version.
     14     
     15     Zotero is distributed in the hope that it will be useful,
     16     but WITHOUT ANY WARRANTY; without even the implied warranty of
     17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18     GNU Affero General Public License for more details.
     19     
     20     You should have received a copy of the GNU Affero General Public License
     21     along with Zotero.  If not, see <http://www.gnu.org/licenses/>.
     22     
     23 	
     24 	Based on nsChromeExtensionHandler example code by Ed Anuff at
     25 	http://kb.mozillazine.org/Dev_:_Extending_the_Chrome_Protocol
     26 	
     27     ***** END LICENSE BLOCK *****
     28 */
     29 
     30 const Cc = Components.classes;
     31 const Ci = Components.interfaces;
     32 
     33 /** XPCOM files to be loaded for all modes **/
     34 const xpcomFilesAll = [
     35 	'zotero',
     36 	'dataDirectory',
     37 	'date',
     38 	'debug',
     39 	'error',
     40 	'file',
     41 	'http',
     42 	'mimeTypeHandler',
     43 	'openurl',
     44 	'ipc',
     45 	'profile',
     46 	'progressWindow',
     47 	'proxy',
     48 	'translation/translate',
     49 	'translation/translate_firefox',
     50 	'translation/translator',
     51 	'translation/tlds',
     52 	'utilities',
     53 	'isbn',
     54 	'utilities_internal',
     55 	'utilities_translate'
     56 ];
     57 
     58 /** XPCOM files to be loaded only for local translation and DB access **/
     59 const xpcomFilesLocal = [
     60 	'libraryTreeView',
     61 	'collectionTreeView',
     62 	'collectionTreeRow',
     63 	'annotate',
     64 	'api',
     65 	'attachments',
     66 	'cite',
     67 	'cookieSandbox',
     68 	'data/library',
     69 	'data/libraries',
     70 	'data/dataObject',
     71 	'data/dataObjects',
     72 	'data/dataObjectUtilities',
     73 	'data/cachedTypes',
     74 	'data/notes',
     75 	'data/item',
     76 	'data/items',
     77 	'data/collection',
     78 	'data/collections',
     79 	'data/feedItem',
     80 	'data/feedItems',
     81 	'data/feed',
     82 	'data/feeds',
     83 	'data/creators',
     84 	'data/group',
     85 	'data/groups',
     86 	'data/itemFields',
     87 	'data/relations',
     88 	'data/search',
     89 	'data/searchConditions',
     90 	'data/searches',
     91 	'data/tags',
     92 	'db',
     93 	'duplicates',
     94 	'feedReader',
     95 	'fulltext',
     96 	'id',
     97 	'integration',
     98 	'itemTreeView',
     99 	'locale',
    100 	'locateManager',
    101 	'mime',
    102 	'notifier',
    103 	'openPDF',
    104 	'quickCopy',
    105 	'recognizePDF',
    106 	'report',
    107 	'router',
    108 	'schema',
    109 	'server',
    110 	'streamer',
    111 	'style',
    112 	'sync',
    113 	'sync/syncAPIClient',
    114 	'sync/syncEngine',
    115 	'sync/syncExceptions',
    116 	'sync/syncEventListeners',
    117 	'sync/syncFullTextEngine',
    118 	'sync/syncLocal',
    119 	'sync/syncRunner',
    120 	'sync/syncUtilities',
    121 	'storage',
    122 	'storage/storageEngine',
    123 	'storage/storageLocal',
    124 	'storage/storageRequest',
    125 	'storage/storageResult',
    126 	'storage/storageUtilities',
    127 	'storage/streamListener',
    128 	'storage/zfs',
    129 	'storage/webdav',
    130 	'syncedSettings',
    131 	'timeline',
    132 	'uri',
    133 	'users',
    134 	'translation/translate_item',
    135 	'translation/translators',
    136 	'connector/httpIntegrationClient',
    137 	'connector/server_connector',
    138 	'connector/server_connectorIntegration',
    139 ];
    140 
    141 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
    142 Components.utils.import("resource://gre/modules/Services.jsm");
    143 
    144 var instanceID = (new Date()).getTime();
    145 var isFirstLoadThisSession = true;
    146 var zContext = null;
    147 var initCallbacks = [];
    148 var zInitOptions = {};
    149 Components.utils.import('resource://zotero/require.js');
    150 
    151 ZoteroContext = function() {}
    152 ZoteroContext.prototype = {
    153 	require,
    154 	
    155 	/**
    156 	 * Convenience method to replicate window.alert()
    157 	 **/
    158 	// TODO: is this still used? if so, move to zotero.js
    159 	"alert":function alert(msg){
    160 		this.Zotero.debug("alert() is deprecated from Zotero XPCOM");
    161 		Cc["@mozilla.org/embedcomp/prompt-service;1"]
    162 			.getService(Ci.nsIPromptService)
    163 			.alert(null, "", msg);
    164 	},
    165 	
    166 	/**
    167 	 * Convenience method to replicate window.confirm()
    168 	 **/
    169 	// TODO: is this still used? if so, move to zotero.js
    170 	"confirm":function confirm(msg){
    171 		this.Zotero.debug("confirm() is deprecated from Zotero XPCOM");
    172 		return Cc["@mozilla.org/embedcomp/prompt-service;1"]
    173 			.getService(Ci.nsIPromptService)
    174 			.confirm(null, "", msg);
    175 	},
    176 	
    177 	"Cc":Cc,
    178 	"Ci":Ci,
    179 	
    180 	/**
    181 	 * Convenience method to replicate window.setTimeout()
    182 	 **/
    183 	"setTimeout":function setTimeout(func, ms){
    184 		return this.Zotero.setTimeout(func, ms);
    185 	},
    186 	
    187 	"clearTimeout":function setTimeout(id) {
    188 		this.Zotero.clearTimeout(id);
    189 	},
    190 	
    191 	/**
    192 	 * Switches in or out of connector mode
    193 	 */
    194 	"switchConnectorMode":function(isConnector) {
    195 		if(isConnector !== this.isConnector) {
    196 			Services.obs.notifyObservers(zContext.Zotero, "zotero-before-reload", isConnector ? "connector" : "full");
    197 			zContext.Zotero.shutdown().then(function() {
    198 				// create a new zContext
    199 				makeZoteroContext(isConnector);
    200 				return zContext.Zotero.init(zInitOptions);
    201 			}).done();
    202 		}
    203 		
    204 		return zContext;
    205 	},
    206 
    207 	/**
    208 	 * Shuts down Zotero, calls a callback (that may return a promise),
    209 	 * then reinitializes Zotero. Returns a promise that is resolved
    210 	 * when this process completes.
    211 	 */
    212 	"reinit":function(cb, isConnector, options = {}) {
    213 		Services.obs.notifyObservers(zContext.Zotero, "zotero-before-reload", isConnector ? "connector" : "full");
    214 		return zContext.Zotero.shutdown().then(function() {
    215 			return cb ? cb() : false;
    216 		}).finally(function() {
    217 			makeZoteroContext(isConnector);
    218 			var o = {};
    219 			Object.assign(o, zInitOptions);
    220 			Object.assign(o, options);
    221 			zContext.Zotero.init(o);
    222 		});
    223 	}
    224 };
    225 
    226 /**
    227  * The class from which the Zotero global XPCOM context is constructed
    228  *
    229  * @constructor
    230  * This runs when ZoteroService is first requested to load all applicable scripts and initialize
    231  * Zotero. Calls to other XPCOM components must be in here rather than in top-level code, as other
    232  * components may not have yet been initialized.
    233  */
    234 function makeZoteroContext(isConnector) {
    235 	if(zContext) {
    236 		// Swap out old zContext
    237 		var oldzContext = zContext;
    238 		// Create new zContext
    239 		zContext = new ZoteroContext();
    240 		// Swap in old Zotero object, so that references don't break, but empty it
    241 		zContext.Zotero = oldzContext.Zotero;
    242 		for(var key in zContext.Zotero) delete zContext.Zotero[key];
    243 	} else {
    244 		zContext = new ZoteroContext();
    245 		zContext.Zotero = function() {};
    246 	}
    247 	
    248 	var subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
    249 	
    250 	// Load zotero.js first
    251 	subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/" + xpcomFilesAll[0] + ".js", zContext);
    252 	
    253 	// Load CiteProc into Zotero.CiteProc namespace
    254 	zContext.Zotero.CiteProc = {"Zotero":zContext.Zotero};
    255 	subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/citeproc.js", zContext.Zotero.CiteProc);
    256 	
    257 	// Load XRegExp object into Zotero.XRegExp
    258 	const xregexpFiles = [
    259 		/**Core functions**/
    260 		'xregexp',
    261 	
    262 		/**Addons**/
    263 		'addons/build',												//adds ability to "build regular expressions using named subpatterns, for readability and pattern reuse"
    264 		'addons/matchrecursive',							//adds ability to "match recursive constructs using XRegExp pattern strings as left and right delimiters"
    265 	
    266 		/**Unicode support**/
    267 		'addons/unicode/unicode-base',				//required for all other unicode packages. Adds \p{Letter} category
    268 	
    269 		//'addons/unicode/unicode-blocks',			//adds support for all Unicode blocks (e.g. InArabic, InCyrillic_Extended_A, etc.)
    270 		'addons/unicode/unicode-categories',	//adds support for all Unicode categories (e.g. Punctuation, Lowercase_Letter, etc.)
    271 		//'addons/unicode/unicode-properties',	//adds Level 1 Unicode properties (e.g. Uppercase, White_Space, etc.)
    272 		//'addons/unicode/unicode-scripts'			//adds support for all Unicode scripts (e.g. Gujarati, Cyrillic, etc.)
    273 		'addons/unicode/unicode-zotero'				//adds support for some Unicode categories used in Zotero
    274 	];
    275 	for (var i=0; i<xregexpFiles.length; i++) {
    276 		subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/xregexp/" + xregexpFiles[i] + ".js", zContext);
    277 	}
    278 	
    279 	// Load remaining xpcomFiles
    280 	for (var i=1; i<xpcomFilesAll.length; i++) {
    281 		try {
    282 			subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/" + xpcomFilesAll[i] + ".js", zContext);
    283 		}
    284 		catch (e) {
    285 			Components.utils.reportError("Error loading " + xpcomFilesAll[i] + ".js", zContext);
    286 			throw (e);
    287 		}
    288 	}
    289 	
    290 	// Load xpcomFiles for specific mode
    291 	for (let xpcomFile of (isConnector ? xpcomFilesConnector : xpcomFilesLocal)) {
    292 		try {
    293 			subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/" + xpcomFile + ".js", zContext, "UTF-8");
    294 		}
    295 		catch (e) {
    296 			dump("Error loading " + xpcomFile + ".js\n\n");
    297 			dump(e + "\n\n");
    298 			Components.utils.reportError("Error loading " + xpcomFile + ".js", zContext);
    299 			throw (e);
    300 		}
    301 	}
    302 	
    303 	// Load RDF files into Zotero.RDF.AJAW namespace (easier than modifying all of the references)
    304 	const rdfXpcomFiles = [
    305 		'rdf/init',
    306 		'rdf/uri',
    307 		'rdf/term',
    308 		'rdf/identity',
    309 		'rdf/match',
    310 		'rdf/n3parser',
    311 		'rdf/rdfparser',
    312 		'rdf/serialize'
    313 	];
    314 	zContext.Zotero.RDF = {Zotero:zContext.Zotero};
    315 	for (var i=0; i<rdfXpcomFiles.length; i++) {
    316 		subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/" + rdfXpcomFiles[i] + ".js", zContext.Zotero.RDF);
    317 	}
    318 	
    319 	if(isStandalone()) {
    320 		// If isStandalone, load standalone.js
    321 		subscriptLoader.loadSubScript("chrome://zotero/content/xpcom/standalone.js", zContext);
    322 	}
    323 	
    324 	// add connector-related properties
    325 	zContext.Zotero.isConnector = isConnector;
    326 	zContext.Zotero.instanceID = instanceID;
    327 	zContext.Zotero.__defineGetter__("isFirstLoadThisSession", function() { return isFirstLoadThisSession; });
    328 };
    329 
    330 /**
    331  * The class representing the Zotero service, and affiliated XPCOM goop
    332  */
    333 function ZoteroService() {
    334 	try {
    335 		var start = Date.now();
    336 		
    337 		if(isFirstLoadThisSession) {
    338 			makeZoteroContext(false);
    339 			zContext.Zotero.init(zInitOptions)
    340 			.catch(function (e) {
    341 				if (e === "ZOTERO_SHOULD_START_AS_CONNECTOR") {
    342 					// if Zotero should start as a connector, reload it
    343 					return zContext.Zotero.shutdown()
    344 					.then(function() {
    345 						makeZoteroContext(true);
    346 						return zContext.Zotero.init(zInitOptions);
    347 					})
    348 				}
    349 				dump(e + "\n\n");
    350 				Components.utils.reportError(e);
    351 				if (!zContext.Zotero.startupError) {
    352 					zContext.Zotero.startupError = e.stack || e;
    353 				}
    354 				if (!isStandalone()) {
    355 					throw e;
    356 				}
    357 			})
    358 			.then(function () {
    359 				if (isStandalone()) {
    360 					if (zContext.Zotero.startupErrorHandler || zContext.Zotero.startupError) {
    361 						if (zContext.Zotero.startupErrorHandler) {
    362 							zContext.Zotero.startupErrorHandler();
    363 						}
    364 						else if (zContext.Zotero.startupError) {
    365 							try {
    366 								zContext.Zotero.startupError =
    367 									zContext.Zotero.Utilities.Internal.filterStack(
    368 										zContext.Zotero.startupError
    369 									);
    370 							}
    371 							catch (e) {}
    372 							
    373 							let ps = Cc["@mozilla.org/embedcomp/prompt-service;1"]
    374 								.getService(Ci.nsIPromptService);
    375 							let buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
    376 								+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
    377 							// Get the stringbundle manually
    378 							let errorStr = "Error";
    379 							let quitStr = "Quit";
    380 							let checkForUpdateStr = "Check for Update";
    381 							try {
    382 								let src = 'chrome://zotero/locale/zotero.properties';
    383 								let stringBundleService = Components.classes["@mozilla.org/intl/stringbundle;1"]
    384 									.getService(Components.interfaces.nsIStringBundleService);
    385 								let stringBundle = stringBundleService.createBundle(src);
    386 								errorStr = stringBundle.GetStringFromName('general.error');
    387 								checkForUpdateStr = stringBundle.GetStringFromName('general.checkForUpdate');
    388 								quitStr = stringBundle.GetStringFromName('general.quit');
    389 							}
    390 							catch (e) {}
    391 							let index = ps.confirmEx(
    392 								null,
    393 								errorStr,
    394 								zContext.Zotero.startupError,
    395 								buttonFlags,
    396 								checkForUpdateStr,
    397 								quitStr,
    398 								null,
    399 								null,
    400 								{}
    401 							);
    402 							if (index == 0) {
    403 								Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
    404 									.getService(Components.interfaces.nsIWindowWatcher)
    405 									.openWindow(null, 'chrome://mozapps/content/update/updates.xul',
    406 										'updateChecker', 'chrome,centerscreen,modal', null);
    407 							}
    408 						}
    409 						zContext.Zotero.Utilities.Internal.quitZotero();
    410 					}
    411 					return;
    412 				}
    413 				zContext.Zotero.debug("Initialized in "+(Date.now() - start)+" ms");
    414 				isFirstLoadThisSession = false;
    415 			});
    416 			
    417 			let cb;
    418 			while (cb = initCallbacks.shift()) {
    419 				cb(zContext.Zotero);
    420 			}
    421 		}
    422 		else {
    423 			zContext.Zotero.debug("Already initialized");
    424 		}
    425 		this.wrappedJSObject = zContext.Zotero;
    426 	} catch(e) {
    427 		var msg = e instanceof Error
    428 			? e.name + ': ' + e.message + '\n' + e.fileName + ':' + e.lineNumber + '\n' + e.stack
    429 			: '' + e;
    430 		dump(msg + '\n');
    431 		Components.utils.reportError(e);
    432 		throw e;
    433 	}
    434 }
    435 
    436 ZoteroService.prototype = {
    437 	contractID: '@zotero.org/Zotero;1',
    438 	classDescription: 'Zotero',
    439 	classID: Components.ID('{e4c61080-ec2d-11da-8ad9-0800200c9a66}'),
    440 	QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports,
    441 			Components.interfaces.nsIProtocolHandler])
    442 }
    443 
    444 function addInitCallback(callback) {
    445 	if (zContext && zContext.Zotero) {
    446 		callback(zContext.Zotero);
    447 	}
    448 	else {
    449 		initCallbacks.push(callback);
    450 	}
    451 }
    452 
    453 var _isStandalone = null;
    454 /**
    455  * Determine whether Zotero Standalone is running
    456  */
    457 function isStandalone() {
    458 	if(_isStandalone === null) {
    459 		var appInfo = Components.classes["@mozilla.org/xre/app-info;1"].
    460 			getService(Components.interfaces.nsIXULAppInfo);
    461 		_isStandalone = appInfo.ID === 'zotero@chnm.gmu.edu';
    462 	}
    463 	return _isStandalone;
    464 }
    465 
    466 function getOS() {
    467 	return Services.appinfo.OS;
    468 }
    469 
    470 function isMac() {
    471 	return getOS() == "Darwin";
    472 }
    473 
    474 function isWin() {
    475 	return getOS() == "WINNT";
    476 }
    477 
    478 function isLinux() {
    479 	return getOS() == "Linux";
    480 }
    481 
    482 /**
    483  * The class representing the Zotero command line handler
    484  */
    485 function ZoteroCommandLineHandler() {}
    486 ZoteroCommandLineHandler.prototype = {
    487 	/* nsICommandLineHandler */
    488 	handle : function(cmdLine) {
    489 		// Force debug output to window
    490 		if (cmdLine.handleFlag("ZoteroDebug", false)) {
    491 			zInitOptions.forceDebugLog = 2;
    492 		}
    493 		// Force debug output to text console
    494 		else if (cmdLine.handleFlag("ZoteroDebugText", false)) {
    495 			zInitOptions.forceDebugLog = 1;
    496 		}
    497 		
    498 		zInitOptions.forceDataDir = cmdLine.handleFlagWithParam("datadir", false);
    499 		
    500 		// handler to open Zotero pane at startup in Zotero for Firefox
    501 		if (!isStandalone() && cmdLine.handleFlag("ZoteroPaneOpen", false)) {
    502 			zInitOptions.openPane = true;
    503 		}
    504 		
    505 		if (cmdLine.handleFlag("ZoteroTest", false)) {
    506 			zInitOptions.test = true;
    507 		}
    508 		if (cmdLine.handleFlag("ZoteroAutomatedTest", false)) {
    509 			zInitOptions.automatedTest = true;
    510 		}
    511 		if (cmdLine.handleFlag("ZoteroSkipBundledFiles", false)) {
    512 			zInitOptions.skipBundledFiles = true;
    513 		}
    514 		
    515 		// handler for Zotero integration commands
    516 		// this is typically used on Windows only, via WM_COPYDATA rather than the command line
    517 		var agent = cmdLine.handleFlagWithParam("ZoteroIntegrationAgent", false);
    518 		if(agent) {
    519 			// Don't open a new window
    520 			cmdLine.preventDefault = true;
    521 			
    522 			var command = cmdLine.handleFlagWithParam("ZoteroIntegrationCommand", false);
    523 			var docId = cmdLine.handleFlagWithParam("ZoteroIntegrationDocument", false);
    524 			
    525 			zContext.Zotero.Integration.execCommand(agent, command, docId);
    526 		}
    527 		
    528 		// handler for Windows IPC commands
    529 		var ipcParam = cmdLine.handleFlagWithParam("ZoteroIPC", false);
    530 		if(ipcParam) {
    531 			// Don't open a new window
    532 			cmdLine.preventDefault = true;
    533 			if (!zContext) new ZoteroService();
    534 			let Zotero = zContext.Zotero;
    535 			Zotero.setTimeout(() => Zotero.IPC.parsePipeInput(ipcParam), 0);
    536 		}
    537 		
    538 		if(isStandalone()) {
    539 			var fileToOpen;
    540 			// Special handler for "zotero" URIs at the command line to prevent them from opening a new window
    541 			var param = cmdLine.handleFlagWithParam("url", false);
    542 			if (param) {
    543 				var uri = cmdLine.resolveURI(param);
    544 				if(uri.schemeIs("zotero")) {
    545 					addInitCallback(function (Zotero) {
    546 						Zotero.uiReadyPromise
    547 						.then(function () {
    548 							// Check for existing window and focus it
    549 							var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
    550 								.getService(Components.interfaces.nsIWindowMediator);
    551 							var win = wm.getMostRecentWindow("navigator:browser");
    552 							if (win) {
    553 								win.focus();
    554 								win.ZoteroPane.loadURI(uri.spec)
    555 							}
    556 						});
    557 					});
    558 				}
    559 				// See below
    560 				else if (uri.schemeIs("file")) {
    561 					Components.utils.import("resource://gre/modules/osfile.jsm")
    562 					fileToOpen = OS.Path.fromFileURI(uri.spec)
    563 				}
    564 				else {
    565 					dump(`Not handling URL: ${uri.spec}\n\n`);
    566 				}
    567 			}
    568 			
    569 			param = cmdLine.handleFlag("debugger", false);
    570 			if (param) {
    571 				try {
    572 					let portOrPath = Services.prefs.getBranch('').getIntPref('devtools.debugger.remote-port');
    573 					
    574 					const { devtools } = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
    575 					const { DebuggerServer } = devtools.require("devtools/server/main");
    576 					
    577 					if (!DebuggerServer.initialized) {
    578 						dump("Initializing devtools server\n");
    579 						DebuggerServer.init();
    580 						DebuggerServer.allowChromeProcess = true;
    581 						DebuggerServer.addBrowserActors();
    582 					}
    583 					
    584 					let listener = DebuggerServer.createListener();
    585 					listener.portOrPath = portOrPath;
    586 					listener.open();
    587 					
    588 					dump("Debugger server started on " + portOrPath + "\n\n");
    589 				}
    590 				catch (e) {
    591 					dump(e + "\n\n");
    592 					Components.utils.reportError(e);
    593 				}
    594 			}
    595 			
    596 			// In Fx49-based Mac Standalone, if Zotero is closed, an associated file is launched, and
    597 			// Zotero hasn't been opened before, a -file parameter is passed and two main windows open.
    598 			// Subsequent file openings when closed result in -url with file:// URLs (converted above)
    599 			// and don't result in two windows. Here we prevent the double window.
    600 			param = fileToOpen;
    601 			if (!param) {
    602 				param = cmdLine.handleFlagWithParam("file", false);
    603 				if (param && isMac()) {
    604 					cmdLine.preventDefault = true;
    605 				}
    606 			}
    607 			if (param) {
    608 				addInitCallback(function (Zotero) {
    609 					// Wait to handle things that require the UI until after it's loaded
    610 					Zotero.uiReadyPromise
    611 					.then(function () {
    612 						var file = Components.classes["@mozilla.org/file/local;1"].
    613 							createInstance(Components.interfaces.nsILocalFile);
    614 						file.initWithPath(param);
    615 						
    616 						if(file.leafName.substr(-4).toLowerCase() === ".csl"
    617 								|| file.leafName.substr(-8).toLowerCase() === ".csl.txt") {
    618 							// Install CSL file
    619 							Zotero.Styles.install({ file: file.path }, file.path);
    620 						} else {
    621 							// Ask before importing
    622 							var checkState = {
    623 								value: Zotero.Prefs.get('import.createNewCollection.fromFileOpenHandler')
    624 							};
    625 							if (Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
    626 									.getService(Components.interfaces.nsIPromptService)
    627 									.confirmCheck(null, Zotero.getString('ingester.importFile.title'),
    628 									Zotero.getString('ingester.importFile.text', [file.leafName]),
    629 									Zotero.getString('ingester.importFile.intoNewCollection'),
    630 									checkState)) {
    631 								Zotero.Prefs.set(
    632 									'import.createNewCollection.fromFileOpenHandler', checkState.value
    633 								);
    634 								
    635 								// Perform file import in front window
    636 								var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
    637 								   .getService(Components.interfaces.nsIWindowMediator);
    638 								var browserWindow = wm.getMostRecentWindow("navigator:browser");
    639 								browserWindow.Zotero_File_Interface.importFile({
    640 									file,
    641 									createNewCollection: checkState.value
    642 								});
    643 							}
    644 						}
    645 					});
    646 				});
    647 			}
    648 		}
    649 	},
    650 	
    651 	contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=zotero",
    652 	classDescription: "Zotero Command Line Handler",
    653 	classID: Components.ID("{531828f8-a16c-46be-b9aa-14845c3b010f}"),
    654 	service: true,
    655 	_xpcom_categories: [{category:"command-line-handler", entry:"m-zotero"}],
    656 	QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsICommandLineHandler,
    657 	                                       Components.interfaces.nsISupports])
    658 };
    659 
    660 var NSGetFactory = XPCOMUtils.generateNSGetFactory([ZoteroService, ZoteroCommandLineHandler]);