1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is Plugin Finder Service.
16
* The Initial Developer of the Original Code is
18
* Portions created by the IBM Corporation are Copyright (C) 2004
19
* IBM Corporation. All Rights Reserved.
22
* Doron Rosenberg <doronr@us.ibm.com>
23
* Alexander Sack <asac@jwsdot.com> - Canonical Ltd.
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the MPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the MPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
39
Components.utils.import("resource://gre/modules/AddonManager.jsm");
41
const DOWNLOAD_STARTED = 0;
42
const DOWNLOAD_FINISHED = 1;
43
const INSTALL_STARTED = 2;
44
const INSTALL_FINISHED = 3;
45
const INSTALLS_COMPLETE = 4;
47
function getLocalizedError(key)
49
return document.getElementById("xpinstallStrings").getString(key);
52
function binaryToHex(input)
54
return [('0' + input.charCodeAt(i).toString(16)).slice(-2)
55
for (i in input)].join('');
58
function verifyHash(aFile, aHash)
61
var [, method, hash] = /^([A-Za-z0-9]+):(.*)$/.exec(aHash);
63
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
64
createInstance(Components.interfaces.nsIFileInputStream);
65
fis.init(aFile, -1, -1, 0);
67
var hasher = Components.classes['@mozilla.org/security/hash;1'].
68
createInstance(Components.interfaces.nsICryptoHash);
69
hasher.initWithString(method);
70
hasher.updateFromStream(fis, -1);
71
dlhash = binaryToHex(hasher.finish(false));
72
return dlhash == hash;
75
Components.utils.reportError(e);
80
function InstallerObserver(aPlugin)
82
this._plugin = aPlugin;
86
InstallerObserver.prototype = {
90
var ios = Components.classes["@mozilla.org/network/io-service;1"].
91
getService(Components.interfaces.nsIIOService);
92
var uri = ios.newURI(this._plugin.InstallerLocation, null, null);
93
uri.QueryInterface(Components.interfaces.nsIURL);
95
// Use a local filename appropriate for the OS
96
var leafName = uri.fileName;
97
var os = Components.classes["@mozilla.org/xre/app-info;1"]
98
.getService(Components.interfaces.nsIXULRuntime)
100
if (os == "WINNT" && leafName.indexOf(".") < 0)
103
var dirs = Components.classes["@mozilla.org/file/directory_service;1"].
104
getService(Components.interfaces.nsIProperties);
106
var resultFile = dirs.get("TmpD", Components.interfaces.nsIFile);
107
resultFile.append(leafName);
108
resultFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,
111
var channel = ios.newChannelFromURI(uri);
113
Components.classes["@mozilla.org/network/downloader;1"].
114
createInstance(Components.interfaces.nsIDownloader);
115
this._downloader.init(this, resultFile);
116
channel.notificationCallbacks = this;
118
this._fireNotification(DOWNLOAD_STARTED, null);
120
channel.asyncOpen(this._downloader, null);
123
Components.utils.reportError(e);
124
this._fireNotification(INSTALL_FINISHED, getLocalizedError("error-228"));
125
if (resultFile && resultFile.exists())
126
resultfile.remove(false);
131
* Inform the gPluginInstaller about what's going on.
133
_fireNotification: function(aStatus, aErrorMsg)
135
gPluginInstaller.pluginXPIInstallationProgress(this._plugin.pid,
138
if (aStatus == INSTALL_FINISHED) {
139
--PluginInstallService._installersPending;
140
PluginInstallService._fireFinishedNotification();
144
QueryInterface: function(iid)
146
if (iid.equals(Components.interfaces.nsISupports) ||
147
iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
148
iid.equals(Components.interfaces.nsIDownloadObserver) ||
149
iid.equals(Components.interfaces.nsIProgressEventSink))
152
throw Components.results.NS_ERROR_NO_INTERFACE;
155
getInterface: function(iid)
157
if (iid.equals(Components.interfaces.nsIProgressEventSink))
163
onDownloadComplete: function(downloader, request, ctxt, status, result)
165
if (!Components.isSuccessCode(status)) {
166
// xpinstall error 228 is "Download Error"
167
this._fireNotification(INSTALL_FINISHED, getLocalizedError("error-228"));
168
result.remove(false);
172
this._fireNotification(DOWNLOAD_FINISHED);
174
if (this._plugin.InstallerHash &&
175
!verifyHash(result, this._plugin.InstallerHash)) {
176
// xpinstall error 261 is "Invalid file hash..."
177
this._fireNotification(INSTALL_FINISHED, getLocalizedError("error-261"));
178
result.remove(false);
182
this._fireNotification(INSTALL_STARTED);
184
result.QueryInterface(Components.interfaces.nsILocalFile);
186
// Make sure the file is executable
187
result.permissions = 0770;
188
var process = Components.classes["@mozilla.org/process/util;1"]
189
.createInstance(Components.interfaces.nsIProcess);
190
process.init(result);
192
process.runAsync([], 0, {
193
observe: function(subject, topic, data) {
194
if (topic != "process-finished") {
195
Components.utils.reportError("Failed to launch installer");
196
self._fireNotification(INSTALL_FINISHED,
197
getLocalizedError("error-207"));
199
else if (process.exitValue != 0) {
200
Components.utils.reportError("Installer returned exit code " + process.exitValue);
201
self._fireNotification(INSTALL_FINISHED,
202
getLocalizedError("error-203"));
205
self._fireNotification(INSTALL_FINISHED, null);
207
result.remove(false);
212
Components.utils.reportError(e);
213
this._fireNotification(INSTALL_FINISHED, getLocalizedError("error-207"));
214
result.remove(false);
218
onProgress: function(aRequest, aContext, aProgress, aProgressMax)
220
gPluginInstaller.pluginInstallationProgressMeter(this._plugin.pid,
225
onStatus: function(aRequest, aContext, aStatus, aStatusArg)
231
var PluginInstallService = {
234
* Start installation of installers and XPI plugins.
235
* @param aInstallerPlugins An array of objects which should have the
236
* properties "pid", "InstallerLocation",
237
* and "InstallerHash"
238
* @param aXPIPlugins An array of objects which should have the
239
* properties "pid", "XPILocation",
242
startPluginInstallation: function (aInstallerPlugins,
245
this._xpiPlugins = aXPIPlugins;
246
this._xpisPending = aXPIPlugins.length;
248
aXPIPlugins.forEach(function(plugin) {
249
AddonManager.getInstallForURL(plugin.XPILocation, function(install) {
250
install.addListener(PluginInstallService);
252
}, "application/x-xpinstall", plugin.XPIHash);
255
// InstallerObserver may finish immediately so we must initialise the
256
// installers after setting the number of installers and xpis pending
257
this._installersPending = aInstallerPlugins.length;
258
this._installerPlugins = [new InstallerObserver(plugin)
259
for each (plugin in aInstallerPlugins)];
262
_fireFinishedNotification: function()
264
if (this._installersPending == 0 && this._xpisPending == 0)
265
gPluginInstaller.pluginXPIInstallationProgress(null, INSTALLS_COMPLETE, null);
268
getPidForInstall: function(install) {
269
for (let i = 0; i < this._xpiPlugins.length; i++) {
270
if (install.sourceURI.spec == this._xpiPlugins[i].XPILocation)
271
return this._xpiPlugins[i].pid;
276
// InstallListener interface
277
onDownloadStarted: function(install) {
278
var pid = this.getPidForInstall(install);
279
gPluginInstaller.pluginXPIInstallationProgress(pid, DOWNLOAD_STARTED, null);
282
onDownloadProgress: function(install) {
283
var pid = this.getPidForInstall(install);
284
gPluginInstaller.pluginXPIInstallationProgressMeter(pid, install.progress,
285
install.maxProgress);
288
onDownloadEnded: function(install) {
289
var pid = this.getPidForInstall(install);
290
gPluginInstaller.pluginXPIInstallationProgress(pid, DOWNLOAD_FINISHED, null);
293
onDownloadFailed: function(install) {
294
var pid = this.getPidForInstall(install);
295
switch (install.error) {
296
case AddonManager.ERROR_NETWORK_FAILURE:
297
var errorMsg = getLocalizedError("error-228");
299
case AddonManager.ERROR_INCORRECT_HASH:
300
var errorMsg = getLocalizedError("error-261");
302
case AddonManager.ERROR_CORRUPT_FILE:
303
var errorMsg = getLocalizedError("error-207");
306
gPluginInstaller.pluginXPIInstallationProgress(pid, INSTALL_FINISHED, errorMsg);
309
this._fireFinishedNotification();
312
onInstallStarted: function(install) {
313
var pid = this.getPidForInstall(install);
314
gPluginInstaller.pluginXPIInstallationProgress(pid, INSTALL_STARTED, null);
317
onInstallEnded: function(install, addon) {
318
var pid = this.getPidForInstall(install);
319
gPluginInstaller.pluginXPIInstallationProgress(pid, INSTALL_FINISHED, null);
322
this._fireFinishedNotification();
325
onInstallFailed: function(install) {
326
var pid = this.getPidForInstall(install);
327
gPluginInstaller.pluginXPIInstallationProgress(pid, INSTALL_FINISHED,
328
getLocalizedError("error-203"));
331
this._fireFinishedNotification();
338
mAptInstallerService: null,
343
install: function(aAptPlugins,
344
aAptInstallerService) {
346
this.mAptInstallerService = aAptInstallerService;
347
this.mAptPlugins = aAptPlugins;
348
this.mRunning = true;
350
// var thread = Components.classes["@mozilla.org/thread;1"]
351
// .createInstance(Components.interfaces.nsIThread);
352
// thread.init(this, 0, nsIThread.PRIORITY_NORMAL, nsIThread.SCOPE_LOCAL, nsIThread.STATE_UNJOINABLE);
358
for (var i = 0; i < this.mAptPlugins.length; i++) {
359
var aptUrl = this.mAptPlugins[i].XPILocation;
360
var aptPid = this.mAptPlugins[i].pid;
361
this.mAptInstallerService.onNotifyStart(aptUrl, aptPid);
364
Components.classes['@mozilla.org/file/local;1']
365
.createInstance(Components.interfaces.nsILocalFile);
367
executable.initWithPath("/usr/bin/apturl");
369
if(!executable.exists() || !executable.isExecutable()) {
370
window.alert('Unexpected error!');
371
this.mAptInstallerService.onNotifyResult(aptUrl, aptPid, -1);
376
Components.classes['@mozilla.org/process/util;1']
377
.createInstance(Components.interfaces.nsIProcess);
379
var nsFile = executable.QueryInterface(Components.interfaces.nsIFile);
381
procUtil.init(executable);
383
var prefBranch = Components.classes["@mozilla.org/preferences-service;1"]
384
.getService(Components.interfaces.nsIPrefBranch);
386
var proxyType = prefBranch.getIntPref("network.proxy.type");
387
var proxyHost = prefBranch.getCharPref("network.proxy.http");
388
var proxyPort = prefBranch.getIntPref("network.proxy.http_port");
391
if(proxyType > 0 && proxyHost != null && proxyHost.length > 0)
393
httpProxy = proxyHost;
396
httpProxy = httpProxy + ":" + proxyPort;
400
var args = new Array();
401
if(httpProxy.length > 0)
403
args = new Array("--http-proxy", httpProxy, aptUrl);
405
args = new Array(aptUrl);
407
procUtil.run(true, args, args.length);
408
res = procUtil.exitValue;
410
this.mAptInstallerService.onNotifyResult(aptUrl, aptPid, res);
413
this.mAptInstallerService.onNotifyResult(null, null, -1 );
419
var PluginAPTInstallService = {
425
pluginPidArray: null,
427
startPluginInstallation: function (aAptPlugins) {
428
AptInstaller.install(aAptPlugins, this);
431
onNotifyStart: function (aptUrl, aptPid) {
432
gPluginInstaller.pluginXPIInstallationProgress(aptPid, 6, null);
435
onNotifyResult: function (aptUrl, aptPid, result) {
437
gPluginInstaller.pluginXPIInstallationProgress(aptPid, 7, "Apt Install Failed or Cancelled");
438
} else if (result == 0) {
439
gPluginInstaller.pluginXPIInstallationProgress(aptPid, 7, null);
441
gPluginInstaller.pluginXPIInstallationProgress(null, 8, null);