Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 3 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | const PROGS_DIR = OS.Constants.Path.winStartMenuProgsDir; |
michael@0 | 6 | const APP_DATA_DIR = OS.Constants.Path.winAppDataDir; |
michael@0 | 7 | |
michael@0 | 8 | /************************************* |
michael@0 | 9 | * Windows app installer |
michael@0 | 10 | * |
michael@0 | 11 | * The Windows installation process will generate the following files: |
michael@0 | 12 | * |
michael@0 | 13 | * ${FolderName} = sanitized app name + "-" + manifest url hash |
michael@0 | 14 | * |
michael@0 | 15 | * %APPDATA%/${FolderName} |
michael@0 | 16 | * - webapp.ini |
michael@0 | 17 | * - webapp.json |
michael@0 | 18 | * - ${AppName}.exe |
michael@0 | 19 | * - ${AppName}.lnk |
michael@0 | 20 | * / uninstall |
michael@0 | 21 | * - webapp-uninstaller.exe |
michael@0 | 22 | * - shortcuts_log.ini |
michael@0 | 23 | * - uninstall.log |
michael@0 | 24 | * / chrome/icons/default/ |
michael@0 | 25 | * - default.ico |
michael@0 | 26 | * |
michael@0 | 27 | * After the app runs for the first time, a profiles/ folder will also be |
michael@0 | 28 | * created which will host the user profile for this app. |
michael@0 | 29 | */ |
michael@0 | 30 | |
michael@0 | 31 | /** |
michael@0 | 32 | * Constructor for the Windows native app shell |
michael@0 | 33 | * |
michael@0 | 34 | * @param aApp {Object} the app object provided to the install function |
michael@0 | 35 | * @param aManifest {Object} the manifest data provided by the web app |
michael@0 | 36 | * @param aCategories {Array} array of app categories |
michael@0 | 37 | * @param aRegistryDir {String} (optional) path to the registry |
michael@0 | 38 | */ |
michael@0 | 39 | function NativeApp(aApp, aManifest, aCategories, aRegistryDir) { |
michael@0 | 40 | CommonNativeApp.call(this, aApp, aManifest, aCategories, aRegistryDir); |
michael@0 | 41 | |
michael@0 | 42 | if (this.isPackaged) { |
michael@0 | 43 | this.size = aApp.updateManifest.size / 1024; |
michael@0 | 44 | } |
michael@0 | 45 | |
michael@0 | 46 | this.webapprt = this.appNameAsFilename + ".exe"; |
michael@0 | 47 | this.configJson = "webapp.json"; |
michael@0 | 48 | this.webappINI = "webapp.ini"; |
michael@0 | 49 | this.iconPath = OS.Path.join("chrome", "icons", "default", "default.ico"); |
michael@0 | 50 | this.uninstallDir = "uninstall"; |
michael@0 | 51 | this.uninstallerFile = OS.Path.join(this.uninstallDir, |
michael@0 | 52 | "webapp-uninstaller.exe"); |
michael@0 | 53 | this.shortcutLogsINI = OS.Path.join(this.uninstallDir, "shortcuts_log.ini"); |
michael@0 | 54 | this.zipFile = "application.zip"; |
michael@0 | 55 | |
michael@0 | 56 | this.backupFiles = [ "chrome", this.configJson, this.webappINI, "uninstall" ]; |
michael@0 | 57 | if (this.isPackaged) { |
michael@0 | 58 | this.backupFiles.push(this.zipFile); |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | this.uninstallSubkeyStr = this.uniqueName; |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | NativeApp.prototype = { |
michael@0 | 65 | __proto__: CommonNativeApp.prototype, |
michael@0 | 66 | size: null, |
michael@0 | 67 | |
michael@0 | 68 | /** |
michael@0 | 69 | * Creates a native installation of the web app in the OS |
michael@0 | 70 | * |
michael@0 | 71 | * @param aManifest {Object} the manifest data provided by the web app |
michael@0 | 72 | * @param aZipPath {String} path to the zip file for packaged apps (undefined |
michael@0 | 73 | * for hosted apps) |
michael@0 | 74 | */ |
michael@0 | 75 | install: Task.async(function*(aManifest, aZipPath) { |
michael@0 | 76 | if (this._dryRun) { |
michael@0 | 77 | return; |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | // If the application is already installed, this is a reinstallation. |
michael@0 | 81 | if (WebappOSUtils.getInstallPath(this.app)) { |
michael@0 | 82 | return yield this.prepareUpdate(aManifest, aZipPath); |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | this._setData(aManifest); |
michael@0 | 86 | |
michael@0 | 87 | let installDir = OS.Path.join(APP_DATA_DIR, this.uniqueName); |
michael@0 | 88 | |
michael@0 | 89 | // Create a temporary installation directory. |
michael@0 | 90 | let dir = getFile(TMP_DIR, this.uniqueName); |
michael@0 | 91 | dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); |
michael@0 | 92 | let tmpDir = dir.path; |
michael@0 | 93 | |
michael@0 | 94 | // Perform the installation in the temp directory. |
michael@0 | 95 | try { |
michael@0 | 96 | yield this._createDirectoryStructure(tmpDir); |
michael@0 | 97 | yield this._getShortcutName(installDir); |
michael@0 | 98 | yield this._copyWebapprt(tmpDir); |
michael@0 | 99 | yield this._copyUninstaller(tmpDir); |
michael@0 | 100 | yield this._createConfigFiles(tmpDir); |
michael@0 | 101 | |
michael@0 | 102 | if (aZipPath) { |
michael@0 | 103 | yield OS.File.move(aZipPath, OS.Path.join(tmpDir, this.zipFile)); |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | yield this._getIcon(tmpDir); |
michael@0 | 107 | } catch (ex) { |
michael@0 | 108 | yield OS.File.removeDir(tmpDir, { ignoreAbsent: true }); |
michael@0 | 109 | throw ex; |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | // Apply the installation. |
michael@0 | 113 | this._removeInstallation(true, installDir); |
michael@0 | 114 | |
michael@0 | 115 | try { |
michael@0 | 116 | yield this._applyTempInstallation(tmpDir, installDir); |
michael@0 | 117 | } catch (ex) { |
michael@0 | 118 | this._removeInstallation(false, installDir); |
michael@0 | 119 | yield OS.File.removeDir(tmpDir, { ignoreAbsent: true }); |
michael@0 | 120 | throw ex; |
michael@0 | 121 | } |
michael@0 | 122 | }), |
michael@0 | 123 | |
michael@0 | 124 | /** |
michael@0 | 125 | * Creates an update in a temporary directory to be applied later. |
michael@0 | 126 | * |
michael@0 | 127 | * @param aManifest {Object} the manifest data provided by the web app |
michael@0 | 128 | * @param aZipPath {String} path to the zip file for packaged apps (undefined |
michael@0 | 129 | * for hosted apps) |
michael@0 | 130 | */ |
michael@0 | 131 | prepareUpdate: Task.async(function*(aManifest, aZipPath) { |
michael@0 | 132 | if (this._dryRun) { |
michael@0 | 133 | return; |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | this._setData(aManifest); |
michael@0 | 137 | |
michael@0 | 138 | let installDir = WebappOSUtils.getInstallPath(this.app); |
michael@0 | 139 | if (!installDir) { |
michael@0 | 140 | throw ERR_NOT_INSTALLED; |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | if (this.uniqueName != OS.Path.basename(installDir)) { |
michael@0 | 144 | // Bug 919799: If the app is still in the registry, migrate its data to |
michael@0 | 145 | // the new format. |
michael@0 | 146 | throw ERR_UPDATES_UNSUPPORTED_OLD_NAMING_SCHEME; |
michael@0 | 147 | } |
michael@0 | 148 | |
michael@0 | 149 | let updateDir = OS.Path.join(installDir, "update"); |
michael@0 | 150 | yield OS.File.removeDir(updateDir, { ignoreAbsent: true }); |
michael@0 | 151 | yield OS.File.makeDir(updateDir); |
michael@0 | 152 | |
michael@0 | 153 | // Perform the update in the "update" subdirectory. |
michael@0 | 154 | try { |
michael@0 | 155 | yield this._createDirectoryStructure(updateDir); |
michael@0 | 156 | yield this._getShortcutName(installDir); |
michael@0 | 157 | yield this._copyUninstaller(updateDir); |
michael@0 | 158 | yield this._createConfigFiles(updateDir); |
michael@0 | 159 | |
michael@0 | 160 | if (aZipPath) { |
michael@0 | 161 | yield OS.File.move(aZipPath, OS.Path.join(updateDir, this.zipFile)); |
michael@0 | 162 | } |
michael@0 | 163 | |
michael@0 | 164 | yield this._getIcon(updateDir); |
michael@0 | 165 | } catch (ex) { |
michael@0 | 166 | yield OS.File.removeDir(updateDir, { ignoreAbsent: true }); |
michael@0 | 167 | throw ex; |
michael@0 | 168 | } |
michael@0 | 169 | }), |
michael@0 | 170 | |
michael@0 | 171 | /** |
michael@0 | 172 | * Applies an update. |
michael@0 | 173 | */ |
michael@0 | 174 | applyUpdate: Task.async(function*() { |
michael@0 | 175 | if (this._dryRun) { |
michael@0 | 176 | return; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | let installDir = WebappOSUtils.getInstallPath(this.app); |
michael@0 | 180 | let updateDir = OS.Path.join(installDir, "update"); |
michael@0 | 181 | |
michael@0 | 182 | yield this._getShortcutName(installDir); |
michael@0 | 183 | |
michael@0 | 184 | let backupDir = yield this._backupInstallation(installDir); |
michael@0 | 185 | |
michael@0 | 186 | try { |
michael@0 | 187 | yield this._applyTempInstallation(updateDir, installDir); |
michael@0 | 188 | } catch (ex) { |
michael@0 | 189 | yield this._restoreInstallation(backupDir, installDir); |
michael@0 | 190 | throw ex; |
michael@0 | 191 | } finally { |
michael@0 | 192 | yield OS.File.removeDir(backupDir, { ignoreAbsent: true }); |
michael@0 | 193 | yield OS.File.removeDir(updateDir, { ignoreAbsent: true }); |
michael@0 | 194 | } |
michael@0 | 195 | }), |
michael@0 | 196 | |
michael@0 | 197 | _applyTempInstallation: Task.async(function*(aTmpDir, aInstallDir) { |
michael@0 | 198 | yield moveDirectory(aTmpDir, aInstallDir); |
michael@0 | 199 | |
michael@0 | 200 | this._createShortcutFiles(aInstallDir); |
michael@0 | 201 | this._writeSystemKeys(aInstallDir); |
michael@0 | 202 | }), |
michael@0 | 203 | |
michael@0 | 204 | _getShortcutName: Task.async(function*(aInstallDir) { |
michael@0 | 205 | let shortcutLogsINIfile = getFile(aInstallDir, this.shortcutLogsINI); |
michael@0 | 206 | |
michael@0 | 207 | if (shortcutLogsINIfile.exists()) { |
michael@0 | 208 | // If it's a reinstallation (or an update) get the shortcut names |
michael@0 | 209 | // from the shortcut_log.ini file |
michael@0 | 210 | let parser = Cc["@mozilla.org/xpcom/ini-processor-factory;1"]. |
michael@0 | 211 | getService(Ci.nsIINIParserFactory). |
michael@0 | 212 | createINIParser(shortcutLogsINIfile); |
michael@0 | 213 | this.shortcutName = parser.getString("STARTMENU", "Shortcut0"); |
michael@0 | 214 | } else { |
michael@0 | 215 | // Check in both directories to see if a shortcut with the same name |
michael@0 | 216 | // already exists. |
michael@0 | 217 | this.shortcutName = yield getAvailableFileName([ PROGS_DIR, DESKTOP_DIR ], |
michael@0 | 218 | this.appNameAsFilename, |
michael@0 | 219 | ".lnk"); |
michael@0 | 220 | } |
michael@0 | 221 | }), |
michael@0 | 222 | |
michael@0 | 223 | /** |
michael@0 | 224 | * Remove the current installation |
michael@0 | 225 | */ |
michael@0 | 226 | _removeInstallation: function(keepProfile, aInstallDir) { |
michael@0 | 227 | let uninstallKey; |
michael@0 | 228 | try { |
michael@0 | 229 | uninstallKey = Cc["@mozilla.org/windows-registry-key;1"]. |
michael@0 | 230 | createInstance(Ci.nsIWindowsRegKey); |
michael@0 | 231 | uninstallKey.open(uninstallKey.ROOT_KEY_CURRENT_USER, |
michael@0 | 232 | "SOFTWARE\\Microsoft\\Windows\\" + |
michael@0 | 233 | "CurrentVersion\\Uninstall", |
michael@0 | 234 | uninstallKey.ACCESS_WRITE); |
michael@0 | 235 | if (uninstallKey.hasChild(this.uninstallSubkeyStr)) { |
michael@0 | 236 | uninstallKey.removeChild(this.uninstallSubkeyStr); |
michael@0 | 237 | } |
michael@0 | 238 | } catch (e) { |
michael@0 | 239 | } finally { |
michael@0 | 240 | if (uninstallKey) { |
michael@0 | 241 | uninstallKey.close(); |
michael@0 | 242 | } |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | let filesToRemove = [ OS.Path.join(DESKTOP_DIR, this.shortcutName), |
michael@0 | 246 | OS.Path.join(PROGS_DIR, this.shortcutName) ]; |
michael@0 | 247 | |
michael@0 | 248 | if (keepProfile) { |
michael@0 | 249 | for (let filePath of this.backupFiles) { |
michael@0 | 250 | filesToRemove.push(OS.Path.join(aInstallDir, filePath)); |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | filesToRemove.push(OS.Path.join(aInstallDir, this.webapprt)); |
michael@0 | 254 | } else { |
michael@0 | 255 | filesToRemove.push(aInstallDir); |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | removeFiles(filesToRemove); |
michael@0 | 259 | }, |
michael@0 | 260 | |
michael@0 | 261 | _backupInstallation: Task.async(function*(aInstallDir) { |
michael@0 | 262 | let backupDir = OS.Path.join(aInstallDir, "backup"); |
michael@0 | 263 | yield OS.File.removeDir(backupDir, { ignoreAbsent: true }); |
michael@0 | 264 | yield OS.File.makeDir(backupDir); |
michael@0 | 265 | |
michael@0 | 266 | for (let filePath of this.backupFiles) { |
michael@0 | 267 | yield OS.File.move(OS.Path.join(aInstallDir, filePath), |
michael@0 | 268 | OS.Path.join(backupDir, filePath)); |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | return backupDir; |
michael@0 | 272 | }), |
michael@0 | 273 | |
michael@0 | 274 | _restoreInstallation: function(aBackupDir, aInstallDir) { |
michael@0 | 275 | return moveDirectory(aBackupDir, aInstallDir); |
michael@0 | 276 | }, |
michael@0 | 277 | |
michael@0 | 278 | /** |
michael@0 | 279 | * Creates the main directory structure. |
michael@0 | 280 | */ |
michael@0 | 281 | _createDirectoryStructure: Task.async(function*(aDir) { |
michael@0 | 282 | yield OS.File.makeDir(OS.Path.join(aDir, this.uninstallDir)); |
michael@0 | 283 | |
michael@0 | 284 | yield OS.File.makeDir(OS.Path.join(aDir, OS.Path.dirname(this.iconPath)), |
michael@0 | 285 | { from: aDir }); |
michael@0 | 286 | }), |
michael@0 | 287 | |
michael@0 | 288 | /** |
michael@0 | 289 | * Copy the webrt executable into the installation directory. |
michael@0 | 290 | */ |
michael@0 | 291 | _copyWebapprt: function(aDir) { |
michael@0 | 292 | return OS.File.copy(OS.Path.join(this.runtimeFolder, "webapprt-stub.exe"), |
michael@0 | 293 | OS.Path.join(aDir, this.webapprt)); |
michael@0 | 294 | }, |
michael@0 | 295 | |
michael@0 | 296 | /** |
michael@0 | 297 | * Copy the uninstaller executable into the installation directory. |
michael@0 | 298 | */ |
michael@0 | 299 | _copyUninstaller: function(aDir) { |
michael@0 | 300 | return OS.File.copy(OS.Path.join(this.runtimeFolder, "webapp-uninstaller.exe"), |
michael@0 | 301 | OS.Path.join(aDir, this.uninstallerFile)); |
michael@0 | 302 | }, |
michael@0 | 303 | |
michael@0 | 304 | /** |
michael@0 | 305 | * Creates the configuration files into their destination folders. |
michael@0 | 306 | */ |
michael@0 | 307 | _createConfigFiles: function(aDir) { |
michael@0 | 308 | // ${InstallDir}/webapp.json |
michael@0 | 309 | yield writeToFile(OS.Path.join(aDir, this.configJson), |
michael@0 | 310 | JSON.stringify(this.webappJson)); |
michael@0 | 311 | |
michael@0 | 312 | let factory = Cc["@mozilla.org/xpcom/ini-processor-factory;1"]. |
michael@0 | 313 | getService(Ci.nsIINIParserFactory); |
michael@0 | 314 | |
michael@0 | 315 | // ${InstallDir}/webapp.ini |
michael@0 | 316 | let webappINIfile = getFile(aDir, this.webappINI); |
michael@0 | 317 | |
michael@0 | 318 | let writer = factory.createINIParser(webappINIfile) |
michael@0 | 319 | .QueryInterface(Ci.nsIINIParserWriter); |
michael@0 | 320 | writer.setString("Webapp", "Name", this.appName); |
michael@0 | 321 | writer.setString("Webapp", "Profile", this.uniqueName); |
michael@0 | 322 | writer.setString("Webapp", "Executable", this.appNameAsFilename); |
michael@0 | 323 | writer.setString("WebappRT", "InstallDir", this.runtimeFolder); |
michael@0 | 324 | writer.writeFile(null, Ci.nsIINIParserWriter.WRITE_UTF16); |
michael@0 | 325 | |
michael@0 | 326 | let shortcutLogsINIfile = getFile(aDir, this.shortcutLogsINI); |
michael@0 | 327 | |
michael@0 | 328 | writer = factory.createINIParser(shortcutLogsINIfile) |
michael@0 | 329 | .QueryInterface(Ci.nsIINIParserWriter); |
michael@0 | 330 | writer.setString("STARTMENU", "Shortcut0", this.shortcutName); |
michael@0 | 331 | writer.setString("DESKTOP", "Shortcut0", this.shortcutName); |
michael@0 | 332 | writer.setString("TASKBAR", "Migrated", "true"); |
michael@0 | 333 | writer.writeFile(null, Ci.nsIINIParserWriter.WRITE_UTF16); |
michael@0 | 334 | |
michael@0 | 335 | // ${UninstallDir}/uninstall.log |
michael@0 | 336 | let uninstallContent = |
michael@0 | 337 | "File: \\webapp.ini\r\n" + |
michael@0 | 338 | "File: \\webapp.json\r\n" + |
michael@0 | 339 | "File: \\webapprt.old\r\n" + |
michael@0 | 340 | "File: \\chrome\\icons\\default\\default.ico"; |
michael@0 | 341 | if (this.isPackaged) { |
michael@0 | 342 | uninstallContent += "\r\nFile: \\application.zip"; |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | yield writeToFile(OS.Path.join(aDir, this.uninstallDir, "uninstall.log"), |
michael@0 | 346 | uninstallContent); |
michael@0 | 347 | }, |
michael@0 | 348 | |
michael@0 | 349 | /** |
michael@0 | 350 | * Writes the keys to the system registry that are necessary for the app |
michael@0 | 351 | * operation and uninstall process. |
michael@0 | 352 | */ |
michael@0 | 353 | _writeSystemKeys: function(aInstallDir) { |
michael@0 | 354 | let parentKey; |
michael@0 | 355 | let uninstallKey; |
michael@0 | 356 | let subKey; |
michael@0 | 357 | |
michael@0 | 358 | try { |
michael@0 | 359 | parentKey = Cc["@mozilla.org/windows-registry-key;1"]. |
michael@0 | 360 | createInstance(Ci.nsIWindowsRegKey); |
michael@0 | 361 | parentKey.open(parentKey.ROOT_KEY_CURRENT_USER, |
michael@0 | 362 | "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", |
michael@0 | 363 | parentKey.ACCESS_WRITE); |
michael@0 | 364 | uninstallKey = parentKey.createChild("Uninstall", parentKey.ACCESS_WRITE) |
michael@0 | 365 | subKey = uninstallKey.createChild(this.uninstallSubkeyStr, |
michael@0 | 366 | uninstallKey.ACCESS_WRITE); |
michael@0 | 367 | |
michael@0 | 368 | subKey.writeStringValue("DisplayName", this.appName); |
michael@0 | 369 | |
michael@0 | 370 | let uninstallerPath = OS.Path.join(aInstallDir, this.uninstallerFile); |
michael@0 | 371 | |
michael@0 | 372 | subKey.writeStringValue("UninstallString", '"' + uninstallerPath + '"'); |
michael@0 | 373 | subKey.writeStringValue("InstallLocation", '"' + aInstallDir + '"'); |
michael@0 | 374 | subKey.writeStringValue("AppFilename", this.appNameAsFilename); |
michael@0 | 375 | subKey.writeStringValue("DisplayIcon", OS.Path.join(aInstallDir, |
michael@0 | 376 | this.iconPath)); |
michael@0 | 377 | |
michael@0 | 378 | let date = new Date(); |
michael@0 | 379 | let year = date.getYear().toString(); |
michael@0 | 380 | let month = date.getMonth(); |
michael@0 | 381 | if (month < 10) { |
michael@0 | 382 | month = "0" + month; |
michael@0 | 383 | } |
michael@0 | 384 | let day = date.getDate(); |
michael@0 | 385 | if (day < 10) { |
michael@0 | 386 | day = "0" + day; |
michael@0 | 387 | } |
michael@0 | 388 | subKey.writeStringValue("InstallDate", year + month + day); |
michael@0 | 389 | if (this.version) { |
michael@0 | 390 | subKey.writeStringValue("DisplayVersion", this.version); |
michael@0 | 391 | } |
michael@0 | 392 | if (this.developerName) { |
michael@0 | 393 | subKey.writeStringValue("Publisher", this.developerName); |
michael@0 | 394 | } |
michael@0 | 395 | subKey.writeStringValue("URLInfoAbout", this.developerUrl); |
michael@0 | 396 | if (this.size) { |
michael@0 | 397 | subKey.writeIntValue("EstimatedSize", this.size); |
michael@0 | 398 | } |
michael@0 | 399 | |
michael@0 | 400 | subKey.writeIntValue("NoModify", 1); |
michael@0 | 401 | subKey.writeIntValue("NoRepair", 1); |
michael@0 | 402 | } catch(ex) { |
michael@0 | 403 | throw ex; |
michael@0 | 404 | } finally { |
michael@0 | 405 | if(subKey) subKey.close(); |
michael@0 | 406 | if(uninstallKey) uninstallKey.close(); |
michael@0 | 407 | if(parentKey) parentKey.close(); |
michael@0 | 408 | } |
michael@0 | 409 | }, |
michael@0 | 410 | |
michael@0 | 411 | /** |
michael@0 | 412 | * Creates a shortcut file inside the app installation folder and makes |
michael@0 | 413 | * two copies of it: one into the desktop and one into the start menu. |
michael@0 | 414 | */ |
michael@0 | 415 | _createShortcutFiles: function(aInstallDir) { |
michael@0 | 416 | let shortcut = getFile(aInstallDir, this.shortcutName). |
michael@0 | 417 | QueryInterface(Ci.nsILocalFileWin); |
michael@0 | 418 | |
michael@0 | 419 | /* function nsILocalFileWin.setShortcut(targetFile, workingDir, args, |
michael@0 | 420 | description, iconFile, iconIndex) */ |
michael@0 | 421 | |
michael@0 | 422 | shortcut.setShortcut(getFile(aInstallDir, this.webapprt), |
michael@0 | 423 | getFile(aInstallDir), |
michael@0 | 424 | null, |
michael@0 | 425 | this.shortDescription, |
michael@0 | 426 | getFile(aInstallDir, this.iconPath), |
michael@0 | 427 | 0); |
michael@0 | 428 | |
michael@0 | 429 | shortcut.copyTo(getFile(DESKTOP_DIR), this.shortcutName); |
michael@0 | 430 | shortcut.copyTo(getFile(PROGS_DIR), this.shortcutName); |
michael@0 | 431 | |
michael@0 | 432 | shortcut.followLinks = false; |
michael@0 | 433 | shortcut.remove(false); |
michael@0 | 434 | }, |
michael@0 | 435 | |
michael@0 | 436 | /** |
michael@0 | 437 | * Process the icon from the imageStream as retrieved from |
michael@0 | 438 | * the URL by getIconForApp(). This will save the icon to the |
michael@0 | 439 | * topwindow.ico file. |
michael@0 | 440 | * |
michael@0 | 441 | * @param aMimeType the icon mimetype |
michael@0 | 442 | * @param aImageStream the stream for the image data |
michael@0 | 443 | * @param aDir the directory where the icon should be stored |
michael@0 | 444 | */ |
michael@0 | 445 | _processIcon: function(aMimeType, aImageStream, aDir) { |
michael@0 | 446 | let deferred = Promise.defer(); |
michael@0 | 447 | |
michael@0 | 448 | let imgTools = Cc["@mozilla.org/image/tools;1"]. |
michael@0 | 449 | createInstance(Ci.imgITools); |
michael@0 | 450 | |
michael@0 | 451 | let imgContainer = imgTools.decodeImage(aImageStream, aMimeType); |
michael@0 | 452 | let iconStream = imgTools.encodeImage(imgContainer, |
michael@0 | 453 | "image/vnd.microsoft.icon", |
michael@0 | 454 | "format=bmp;bpp=32"); |
michael@0 | 455 | |
michael@0 | 456 | let tmpIconFile = getFile(aDir, this.iconPath); |
michael@0 | 457 | |
michael@0 | 458 | let outputStream = FileUtils.openSafeFileOutputStream(tmpIconFile); |
michael@0 | 459 | NetUtil.asyncCopy(iconStream, outputStream, function(aResult) { |
michael@0 | 460 | if (Components.isSuccessCode(aResult)) { |
michael@0 | 461 | deferred.resolve(); |
michael@0 | 462 | } else { |
michael@0 | 463 | deferred.reject("Failure copying icon: " + aResult); |
michael@0 | 464 | } |
michael@0 | 465 | }); |
michael@0 | 466 | |
michael@0 | 467 | return deferred.promise; |
michael@0 | 468 | } |
michael@0 | 469 | } |