ogre.rb 0.1-i686-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +79 -0
- data/Rakefile +288 -0
- data/doc_src/ogre.rb +246 -0
- data/doc_src/ois.rb +67 -0
- data/lib/application.rb +146 -0
- data/lib/application_frame_listener.rb +302 -0
- data/lib/application_loading_bar.rb +115 -0
- data/lib/constants.rb +51 -0
- data/lib/method_fixes.rb +42 -0
- data/lib/ogre.so +0 -0
- data/lib/ruby_ois.so +0 -0
- data/ogre.rb +25 -0
- data/platform.rb +23 -0
- data/samples/Ogre.log +261 -0
- data/samples/bsp.rb +76 -0
- data/samples/cg.dll +0 -0
- data/samples/grass.rb +325 -0
- data/samples/js3250.dll +0 -0
- data/samples/lighting.rb +138 -0
- data/samples/media/materials/programs/Grass.cg +30 -0
- data/samples/media/materials/programs/OffsetMapping.cg +97 -0
- data/samples/media/materials/programs/OffsetMapping.hlsl +135 -0
- data/samples/media/materials/programs/OffsetMappingFp.glsl +69 -0
- data/samples/media/materials/programs/OffsetMappingVp.glsl +54 -0
- data/samples/media/materials/programs/OffsetMapping_specular.asm +44 -0
- data/samples/media/materials/scripts/CloudySky.material +17 -0
- data/samples/media/materials/scripts/CubeMapping.material +34 -0
- data/samples/media/materials/scripts/Flare.material +17 -0
- data/samples/media/materials/scripts/Grass.material +63 -0
- data/samples/media/materials/scripts/Knot.material +14 -0
- data/samples/media/materials/scripts/MorningSkyBox.material +17 -0
- data/samples/media/materials/scripts/Offset.material +124 -0
- data/samples/media/materials/scripts/Ogre.material +119 -0
- data/samples/media/materials/scripts/RZR-002.material +15 -0
- data/samples/media/materials/scripts/Razor.material +14 -0
- data/samples/media/materials/scripts/Ribbon.material +19 -0
- data/samples/media/materials/scripts/RustySteel.material +14 -0
- data/samples/media/materials/scripts/SpaceSkyBox.material +17 -0
- data/samples/media/materials/scripts/SpaceSkyPlane.material +17 -0
- data/samples/media/materials/scripts/TextureEffects.material +15 -0
- data/samples/media/materials/scripts/dragon.material +42 -0
- data/samples/media/materials/scripts/smoke.material +18 -0
- data/samples/media/materials/textures/GreenSkin.jpg +0 -0
- data/samples/media/materials/textures/MtlPlat2.jpg +0 -0
- data/samples/media/materials/textures/RZR-002.png +0 -0
- data/samples/media/materials/textures/RustedMetal.jpg +0 -0
- data/samples/media/materials/textures/RustySteel.jpg +0 -0
- data/samples/media/materials/textures/Water02.jpg +0 -0
- data/samples/media/materials/textures/WeirdEye.png +0 -0
- data/samples/media/materials/textures/clouds.jpg +0 -0
- data/samples/media/materials/textures/cursor.png +0 -0
- data/samples/media/materials/textures/dirt01.jpg +0 -0
- data/samples/media/materials/textures/flare.png +0 -0
- data/samples/media/materials/textures/gras_02.png +0 -0
- data/samples/media/materials/textures/grass_1024.jpg +0 -0
- data/samples/media/materials/textures/ogreborder.png +0 -0
- data/samples/media/materials/textures/ogreborderUp.png +0 -0
- data/samples/media/materials/textures/ribbonband.png +0 -0
- data/samples/media/materials/textures/rockwall.tga +0 -0
- data/samples/media/materials/textures/rockwall_NH.tga +0 -0
- data/samples/media/materials/textures/smoke.png +0 -0
- data/samples/media/materials/textures/smokecolors.png +0 -0
- data/samples/media/materials/textures/spacesky.jpg +0 -0
- data/samples/media/materials/textures/spheremap.png +0 -0
- data/samples/media/materials/textures/texmap2.jpg +0 -0
- data/samples/media/models/RZR-002.mesh +0 -0
- data/samples/media/models/geosphere4500.mesh +0 -0
- data/samples/media/models/geosphere8000.mesh +0 -0
- data/samples/media/models/knot.mesh +0 -0
- data/samples/media/models/ogrehead.mesh +0 -0
- data/samples/media/models/razor.mesh +0 -0
- data/samples/media/models/sphere.mesh +0 -0
- data/samples/media/overlays/CubeMapping.overlay +139 -0
- data/samples/media/packs/OgreCore.zip +0 -0
- data/samples/media/packs/chiropteraDM.pk3 +0 -0
- data/samples/media/packs/chiropteraDM.txt +99 -0
- data/samples/media/packs/cubemap.zip +0 -0
- data/samples/media/packs/cubemapsJS.zip +0 -0
- data/samples/media/packs/dragon.zip +0 -0
- data/samples/media/packs/skybox.zip +0 -0
- data/samples/media/particles/smoke.particle +43 -0
- data/samples/media.cfg +22 -0
- data/samples/navi/Media/NaviDemo.material +60 -0
- data/samples/navi/Media/OgreCore.zip +0 -0
- data/samples/navi/Media/cerulean.jpg +0 -0
- data/samples/navi/Media/clouds.jpg +0 -0
- data/samples/navi/Media/controlsNaviMask.png +0 -0
- data/samples/navi/Media/grass.jpg +0 -0
- data/samples/navi/Media/knot.mesh +0 -0
- data/samples/navi/Media/testNaviMask.png +0 -0
- data/samples/navi/NaviLocal/Navi.js +136 -0
- data/samples/navi/NaviLocal/buttonBg.jpg +0 -0
- data/samples/navi/NaviLocal/controls.html +303 -0
- data/samples/navi/NaviLocal/knobBg.jpg +0 -0
- data/samples/navi/NaviLocal/moo.dropdownmenu.js +87 -0
- data/samples/navi/NaviLocal/mootools.v1.1.js +6964 -0
- data/samples/navi/NaviLocal/naviLogo.html +32 -0
- data/samples/navi/NaviLocal/naviLogo.png +0 -0
- data/samples/navi/NaviLocal/pageBg.jpg +0 -0
- data/samples/navi/NaviLocal/sliderBg.jpg +0 -0
- data/samples/navi/NaviLocal/test.html +5 -0
- data/samples/navi/NaviLocal/welcome.html +36 -0
- data/samples/navi/NaviLocal/welcome.png +0 -0
- data/samples/navi/chrome/chromelist.txt +597 -0
- data/samples/navi/chrome/classic.jar +0 -0
- data/samples/navi/chrome/classic.manifest +4 -0
- data/samples/navi/chrome/comm.jar +0 -0
- data/samples/navi/chrome/comm.manifest +2 -0
- data/samples/navi/chrome/en-US.jar +0 -0
- data/samples/navi/chrome/en-US.manifest +9 -0
- data/samples/navi/chrome/toolkit.jar +0 -0
- data/samples/navi/chrome/toolkit.manifest +6 -0
- data/samples/navi/components/FeedProcessor.js +1825 -0
- data/samples/navi/components/alerts.xpt +0 -0
- data/samples/navi/components/appshell.xpt +0 -0
- data/samples/navi/components/appstartup.xpt +0 -0
- data/samples/navi/components/auth.dll +0 -0
- data/samples/navi/components/autocomplete.xpt +0 -0
- data/samples/navi/components/autoconfig.dll +0 -0
- data/samples/navi/components/autoconfig.xpt +0 -0
- data/samples/navi/components/caps.xpt +0 -0
- data/samples/navi/components/chardet.xpt +0 -0
- data/samples/navi/components/chrome.xpt +0 -0
- data/samples/navi/components/commandhandler.xpt +0 -0
- data/samples/navi/components/commandlines.xpt +0 -0
- data/samples/navi/components/composer.xpt +0 -0
- data/samples/navi/components/compreg.dat +1474 -0
- data/samples/navi/components/content_base.xpt +0 -0
- data/samples/navi/components/content_html.xpt +0 -0
- data/samples/navi/components/content_htmldoc.xpt +0 -0
- data/samples/navi/components/content_xmldoc.xpt +0 -0
- data/samples/navi/components/content_xslt.xpt +0 -0
- data/samples/navi/components/content_xtf.xpt +0 -0
- data/samples/navi/components/directory.xpt +0 -0
- data/samples/navi/components/docshell_base.xpt +0 -0
- data/samples/navi/components/dom.xpt +0 -0
- data/samples/navi/components/dom_base.xpt +0 -0
- data/samples/navi/components/dom_canvas.xpt +0 -0
- data/samples/navi/components/dom_core.xpt +0 -0
- data/samples/navi/components/dom_css.xpt +0 -0
- data/samples/navi/components/dom_events.xpt +0 -0
- data/samples/navi/components/dom_html.xpt +0 -0
- data/samples/navi/components/dom_loadsave.xpt +0 -0
- data/samples/navi/components/dom_range.xpt +0 -0
- data/samples/navi/components/dom_sidebar.xpt +0 -0
- data/samples/navi/components/dom_storage.xpt +0 -0
- data/samples/navi/components/dom_stylesheets.xpt +0 -0
- data/samples/navi/components/dom_svg.xpt +0 -0
- data/samples/navi/components/dom_traversal.xpt +0 -0
- data/samples/navi/components/dom_views.xpt +0 -0
- data/samples/navi/components/dom_xbl.xpt +0 -0
- data/samples/navi/components/dom_xpath.xpt +0 -0
- data/samples/navi/components/dom_xul.xpt +0 -0
- data/samples/navi/components/downloads.xpt +0 -0
- data/samples/navi/components/editor.xpt +0 -0
- data/samples/navi/components/embed_base.xpt +0 -0
- data/samples/navi/components/extensions.xpt +0 -0
- data/samples/navi/components/exthandler.xpt +0 -0
- data/samples/navi/components/fastfind.xpt +0 -0
- data/samples/navi/components/feeds.xpt +0 -0
- data/samples/navi/components/find.xpt +0 -0
- data/samples/navi/components/gfx.xpt +0 -0
- data/samples/navi/components/gksvgrenderer.xpt +0 -0
- data/samples/navi/components/history.xpt +0 -0
- data/samples/navi/components/htmlparser.xpt +0 -0
- data/samples/navi/components/imglib2.xpt +0 -0
- data/samples/navi/components/inspector.xpt +0 -0
- data/samples/navi/components/intl.xpt +0 -0
- data/samples/navi/components/intlcmpt.xpt +0 -0
- data/samples/navi/components/jar.xpt +0 -0
- data/samples/navi/components/jsconsole-clhandler.js +170 -0
- data/samples/navi/components/jsconsole.xpt +0 -0
- data/samples/navi/components/jsdservice.xpt +0 -0
- data/samples/navi/components/layout_base.xpt +0 -0
- data/samples/navi/components/layout_printing.xpt +0 -0
- data/samples/navi/components/layout_xul.xpt +0 -0
- data/samples/navi/components/layout_xul_tree.xpt +0 -0
- data/samples/navi/components/locale.xpt +0 -0
- data/samples/navi/components/lwbrk.xpt +0 -0
- data/samples/navi/components/mimetype.xpt +0 -0
- data/samples/navi/components/mozbrwsr.xpt +0 -0
- data/samples/navi/components/mozfind.xpt +0 -0
- data/samples/navi/components/necko.xpt +0 -0
- data/samples/navi/components/necko_about.xpt +0 -0
- data/samples/navi/components/necko_cache.xpt +0 -0
- data/samples/navi/components/necko_cookie.xpt +0 -0
- data/samples/navi/components/necko_data.xpt +0 -0
- data/samples/navi/components/necko_dns.xpt +0 -0
- data/samples/navi/components/necko_file.xpt +0 -0
- data/samples/navi/components/necko_ftp.xpt +0 -0
- data/samples/navi/components/necko_http.xpt +0 -0
- data/samples/navi/components/necko_res.xpt +0 -0
- data/samples/navi/components/necko_socket.xpt +0 -0
- data/samples/navi/components/necko_strconv.xpt +0 -0
- data/samples/navi/components/necko_viewsource.xpt +0 -0
- data/samples/navi/components/nsCloseAllWindows.js +143 -0
- data/samples/navi/components/nsDefaultCLH.js +231 -0
- data/samples/navi/components/nsDictionary.js +148 -0
- data/samples/navi/components/nsExtensionManager.js +8497 -0
- data/samples/navi/components/nsHelperAppDlg.js +990 -0
- data/samples/navi/components/nsInterfaceInfoToIDL.js +590 -0
- data/samples/navi/components/nsKillAll.js +200 -0
- data/samples/navi/components/nsPostUpdateWin.js +711 -0
- data/samples/navi/components/nsProgressDialog.js +949 -0
- data/samples/navi/components/nsProxyAutoConfig.js +396 -0
- data/samples/navi/components/nsResetPref.js +175 -0
- data/samples/navi/components/nsURLFormatter.js +179 -0
- data/samples/navi/components/nsUpdateService.js +3074 -0
- data/samples/navi/components/nsXULAppInstall.js +301 -0
- data/samples/navi/components/nsXmlRpcClient.js +1038 -0
- data/samples/navi/components/oji.xpt +0 -0
- data/samples/navi/components/passwordmgr.xpt +0 -0
- data/samples/navi/components/pipboot.xpt +0 -0
- data/samples/navi/components/pipnss.xpt +0 -0
- data/samples/navi/components/plugin.xpt +0 -0
- data/samples/navi/components/pref.xpt +0 -0
- data/samples/navi/components/prefetch.xpt +0 -0
- data/samples/navi/components/profile.xpt +0 -0
- data/samples/navi/components/progressDlg.xpt +0 -0
- data/samples/navi/components/proxyObject.xpt +0 -0
- data/samples/navi/components/rdf.xpt +0 -0
- data/samples/navi/components/satchel.xpt +0 -0
- data/samples/navi/components/saxparser.xpt +0 -0
- data/samples/navi/components/shistory.xpt +0 -0
- data/samples/navi/components/storage.xpt +0 -0
- data/samples/navi/components/toolkitprofile.xpt +0 -0
- data/samples/navi/components/transformiix.dll +0 -0
- data/samples/navi/components/txmgr.xpt +0 -0
- data/samples/navi/components/txtsvc.xpt +0 -0
- data/samples/navi/components/uconv.xpt +0 -0
- data/samples/navi/components/unicharutil.xpt +0 -0
- data/samples/navi/components/universalchardet.dll +0 -0
- data/samples/navi/components/update.xpt +0 -0
- data/samples/navi/components/uriloader.xpt +0 -0
- data/samples/navi/components/urlformatter.xpt +0 -0
- data/samples/navi/components/webBrowser_core.xpt +0 -0
- data/samples/navi/components/webbrowserpersist.xpt +0 -0
- data/samples/navi/components/webshell_idls.xpt +0 -0
- data/samples/navi/components/websrvcs.dll +0 -0
- data/samples/navi/components/websrvcs.xpt +0 -0
- data/samples/navi/components/widget.xpt +0 -0
- data/samples/navi/components/windowds.xpt +0 -0
- data/samples/navi/components/windowwatcher.xpt +0 -0
- data/samples/navi/components/xml-rpc.xpt +0 -0
- data/samples/navi/components/xmlextras.dll +0 -0
- data/samples/navi/components/xpcom_base.xpt +0 -0
- data/samples/navi/components/xpcom_components.xpt +0 -0
- data/samples/navi/components/xpcom_ds.xpt +0 -0
- data/samples/navi/components/xpcom_io.xpt +0 -0
- data/samples/navi/components/xpcom_obsolete.xpt +0 -0
- data/samples/navi/components/xpcom_thread.xpt +0 -0
- data/samples/navi/components/xpcom_xpti.xpt +0 -0
- data/samples/navi/components/xpconnect.xpt +0 -0
- data/samples/navi/components/xpinstall.xpt +0 -0
- data/samples/navi/components/xpti.dat +1424 -0
- data/samples/navi/components/xulapp.xpt +0 -0
- data/samples/navi/components/xulapp_setup.xpt +0 -0
- data/samples/navi/components/xuldoc.xpt +0 -0
- data/samples/navi/components/xulrunner.xpt +0 -0
- data/samples/navi/components/xultmpl.xpt +0 -0
- data/samples/navi/components/xulutil.dll +0 -0
- data/samples/navi/controlsNaviMask.png +0 -0
- data/samples/navi/greprefs/all.js +1344 -0
- data/samples/navi/greprefs/security-prefs.js +69 -0
- data/samples/navi/greprefs/xpinstall.js +2 -0
- data/samples/navi/navi_demo.rb +207 -0
- data/samples/navi/plugins/NPSWF32.dll +0 -0
- data/samples/navi/plugins/flashplayer.xpt +0 -0
- data/samples/navi/plugins/npnul32.dll +0 -0
- data/samples/navi/plugins.cfg +10 -0
- data/samples/navi/res/EditorOverride.css +359 -0
- data/samples/navi/res/Thumbs.db +0 -0
- data/samples/navi/res/arrow.gif +0 -0
- data/samples/navi/res/arrowd.gif +0 -0
- data/samples/navi/res/bloatcycle.html +40 -0
- data/samples/navi/res/broken-image.gif +0 -0
- data/samples/navi/res/charsetData.properties +199 -0
- data/samples/navi/res/charsetalias.properties +517 -0
- data/samples/navi/res/cmessage.txt +1 -0
- data/samples/navi/res/dtd/xhtml11.dtd +300 -0
- data/samples/navi/res/entityTables/html40Latin1.properties +146 -0
- data/samples/navi/res/entityTables/html40Special.properties +69 -0
- data/samples/navi/res/entityTables/html40Symbols.properties +164 -0
- data/samples/navi/res/entityTables/htmlEntityVersions.properties +50 -0
- data/samples/navi/res/entityTables/transliterate.properties +2367 -0
- data/samples/navi/res/fonts/fontEncoding.properties +127 -0
- data/samples/navi/res/fonts/fontNameMap.properties +134 -0
- data/samples/navi/res/forms.css +531 -0
- data/samples/navi/res/grabber.gif +0 -0
- data/samples/navi/res/hiddenWindow.html +1 -0
- data/samples/navi/res/html/Thumbs.db +0 -0
- data/samples/navi/res/html/gopher-audio.gif +0 -0
- data/samples/navi/res/html/gopher-binary.gif +0 -0
- data/samples/navi/res/html/gopher-find.gif +0 -0
- data/samples/navi/res/html/gopher-image.gif +0 -0
- data/samples/navi/res/html/gopher-menu.gif +0 -0
- data/samples/navi/res/html/gopher-movie.gif +0 -0
- data/samples/navi/res/html/gopher-sound.gif +0 -0
- data/samples/navi/res/html/gopher-telnet.gif +0 -0
- data/samples/navi/res/html/gopher-text.gif +0 -0
- data/samples/navi/res/html/gopher-unknown.gif +0 -0
- data/samples/navi/res/html.css +478 -0
- data/samples/navi/res/langGroups.properties +236 -0
- data/samples/navi/res/language.properties +259 -0
- data/samples/navi/res/loading-image.gif +0 -0
- data/samples/navi/res/quirk.css +282 -0
- data/samples/navi/res/samples/Anieyes.gif +0 -0
- data/samples/navi/res/samples/Thumbs.db +0 -0
- data/samples/navi/res/samples/aform.css +69 -0
- data/samples/navi/res/samples/beeptest.html +18 -0
- data/samples/navi/res/samples/bform.css +45 -0
- data/samples/navi/res/samples/bg.jpg +0 -0
- data/samples/navi/res/samples/cform.css +40 -0
- data/samples/navi/res/samples/checkboxTest.xul +47 -0
- data/samples/navi/res/samples/demoform.css +97 -0
- data/samples/navi/res/samples/find.html +97 -0
- data/samples/navi/res/samples/gear1.gif +0 -0
- data/samples/navi/res/samples/image_props.html +58 -0
- data/samples/navi/res/samples/mozform.css +256 -0
- data/samples/navi/res/samples/printsetup.html +175 -0
- data/samples/navi/res/samples/raptor.jpg +0 -0
- data/samples/navi/res/samples/rock_gra.gif +0 -0
- data/samples/navi/res/samples/scrollbarTest1.xul +66 -0
- data/samples/navi/res/samples/scrollbarTest2.xul +19 -0
- data/samples/navi/res/samples/sliderTest1.xul +14 -0
- data/samples/navi/res/samples/soundtest.html +20 -0
- data/samples/navi/res/samples/test.wav +0 -0
- data/samples/navi/res/samples/test0.html +220 -0
- data/samples/navi/res/samples/test1.html +84 -0
- data/samples/navi/res/samples/test10.html +16 -0
- data/samples/navi/res/samples/test11.html +42 -0
- data/samples/navi/res/samples/test12.html +79 -0
- data/samples/navi/res/samples/test13.html +126 -0
- data/samples/navi/res/samples/test14.html +5 -0
- data/samples/navi/res/samples/test15.html +5 -0
- data/samples/navi/res/samples/test16.html +124 -0
- data/samples/navi/res/samples/test2.html +41 -0
- data/samples/navi/res/samples/test3.html +126 -0
- data/samples/navi/res/samples/test4.html +335 -0
- data/samples/navi/res/samples/test5.html +199 -0
- data/samples/navi/res/samples/test6.html +335 -0
- data/samples/navi/res/samples/test7.html +11 -0
- data/samples/navi/res/samples/test8-1.html +66 -0
- data/samples/navi/res/samples/test8.html +662 -0
- data/samples/navi/res/samples/test8dom.html +64 -0
- data/samples/navi/res/samples/test8sca.html +308 -0
- data/samples/navi/res/samples/test8siz.html +224 -0
- data/samples/navi/res/samples/test8tab.html +9 -0
- data/samples/navi/res/samples/test9.html +12 -0
- data/samples/navi/res/samples/test9a.html +39 -0
- data/samples/navi/res/samples/test9b.html +16 -0
- data/samples/navi/res/samples/test_ed.html +5 -0
- data/samples/navi/res/samples/test_form.html +34 -0
- data/samples/navi/res/samples/test_gfx.html +75 -0
- data/samples/navi/res/samples/test_lbox.html +100 -0
- data/samples/navi/res/samples/test_pr.html +87 -0
- data/samples/navi/res/samples/test_weight.html +45 -0
- data/samples/navi/res/samples/toolbarTest1.xul +51 -0
- data/samples/navi/res/samples/treeTest1.css +62 -0
- data/samples/navi/res/samples/treeTest1.xul +110 -0
- data/samples/navi/res/samples/xulTest.css +130 -0
- data/samples/navi/res/svg.css +64 -0
- data/samples/navi/res/table-add-column-after-active.gif +0 -0
- data/samples/navi/res/table-add-column-after-hover.gif +0 -0
- data/samples/navi/res/table-add-column-after.gif +0 -0
- data/samples/navi/res/table-add-column-before-active.gif +0 -0
- data/samples/navi/res/table-add-column-before-hover.gif +0 -0
- data/samples/navi/res/table-add-column-before.gif +0 -0
- data/samples/navi/res/table-add-row-after-active.gif +0 -0
- data/samples/navi/res/table-add-row-after-hover.gif +0 -0
- data/samples/navi/res/table-add-row-after.gif +0 -0
- data/samples/navi/res/table-add-row-before-active.gif +0 -0
- data/samples/navi/res/table-add-row-before-hover.gif +0 -0
- data/samples/navi/res/table-add-row-before.gif +0 -0
- data/samples/navi/res/table-remove-column-active.gif +0 -0
- data/samples/navi/res/table-remove-column-hover.gif +0 -0
- data/samples/navi/res/table-remove-column.gif +0 -0
- data/samples/navi/res/table-remove-row-active.gif +0 -0
- data/samples/navi/res/table-remove-row-hover.gif +0 -0
- data/samples/navi/res/table-remove-row.gif +0 -0
- data/samples/navi/res/throbber/Thumbs.db +0 -0
- data/samples/navi/res/throbber/anim.gif +0 -0
- data/samples/navi/res/throbber/anims00.gif +0 -0
- data/samples/navi/res/throbber/anims01.gif +0 -0
- data/samples/navi/res/throbber/anims02.gif +0 -0
- data/samples/navi/res/throbber/anims03.gif +0 -0
- data/samples/navi/res/throbber/anims04.gif +0 -0
- data/samples/navi/res/throbber/anims05.gif +0 -0
- data/samples/navi/res/throbber/anims06.gif +0 -0
- data/samples/navi/res/throbber/anims07.gif +0 -0
- data/samples/navi/res/throbber/anims08.gif +0 -0
- data/samples/navi/res/throbber/anims09.gif +0 -0
- data/samples/navi/res/throbber/anims10.gif +0 -0
- data/samples/navi/res/throbber/anims11.gif +0 -0
- data/samples/navi/res/throbber/anims12.gif +0 -0
- data/samples/navi/res/throbber/anims13.gif +0 -0
- data/samples/navi/res/throbber/anims14.gif +0 -0
- data/samples/navi/res/throbber/anims15.gif +0 -0
- data/samples/navi/res/throbber/anims16.gif +0 -0
- data/samples/navi/res/throbber/anims17.gif +0 -0
- data/samples/navi/res/throbber/anims18.gif +0 -0
- data/samples/navi/res/throbber/anims19.gif +0 -0
- data/samples/navi/res/throbber/anims20.gif +0 -0
- data/samples/navi/res/throbber/anims21.gif +0 -0
- data/samples/navi/res/throbber/anims22.gif +0 -0
- data/samples/navi/res/throbber/anims23.gif +0 -0
- data/samples/navi/res/throbber/anims24.gif +0 -0
- data/samples/navi/res/throbber/anims25.gif +0 -0
- data/samples/navi/res/throbber/anims26.gif +0 -0
- data/samples/navi/res/throbber/anims27.gif +0 -0
- data/samples/navi/res/throbber/anims28.gif +0 -0
- data/samples/navi/res/throbber/anims29.gif +0 -0
- data/samples/navi/res/ua.css +235 -0
- data/samples/navi/res/viewer.properties +1 -0
- data/samples/navi/res/viewsource.css +118 -0
- data/samples/navi/res/wincharset.properties +55 -0
- data/samples/navi/resources.cfg +14 -0
- data/samples/navi/testNaviMask.png +0 -0
- data/samples/ogre.cfg +8 -0
- data/samples/plugins.cfg +11 -0
- data/samples/quake3settings.cfg +2 -0
- data/samples/render_run_log.5796 +891 -0
- data/samples/render_to_texture.rb +161 -0
- data/samples/resources.cfg +16 -0
- data/samples/sky_box.rb +107 -0
- data/samples/sky_dome.rb +86 -0
- data/samples/sky_plane.rb +27 -0
- data/samples/smoke.rb +23 -0
- data/samples/work/cube_mapping.rb +686 -0
- metadata +500 -0
@@ -0,0 +1,3074 @@
|
|
1
|
+
//@line 42 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2
|
+
|
3
|
+
const PREF_APP_UPDATE_ENABLED = "app.update.enabled";
|
4
|
+
const PREF_APP_UPDATE_AUTO = "app.update.auto";
|
5
|
+
const PREF_APP_UPDATE_MODE = "app.update.mode";
|
6
|
+
const PREF_APP_UPDATE_SILENT = "app.update.silent";
|
7
|
+
const PREF_APP_UPDATE_INTERVAL = "app.update.interval";
|
8
|
+
const PREF_APP_UPDATE_TIMER = "app.update.timer";
|
9
|
+
const PREF_APP_UPDATE_LOG_BRANCH = "app.update.log.";
|
10
|
+
const PREF_APP_UPDATE_URL = "app.update.url";
|
11
|
+
const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override";
|
12
|
+
const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details";
|
13
|
+
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
|
14
|
+
const PREF_APP_UPDATE_SHOW_INSTALLED_UI = "app.update.showInstalledUI";
|
15
|
+
const PREF_APP_UPDATE_LASTUPDATETIME_FMT = "app.update.lastUpdateTime.%ID%";
|
16
|
+
const PREF_APP_EXTENSIONS_VERSION = "app.extensions.version";
|
17
|
+
const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale";
|
18
|
+
const PREF_APP_UPDATE_INCOMPATIBLE_MODE = "app.update.incompatible.mode";
|
19
|
+
const PREF_UPDATE_NEVER_BRANCH = "app.update.never."
|
20
|
+
const PREF_PARTNER_BRANCH = "app.partner.";
|
21
|
+
|
22
|
+
const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul";
|
23
|
+
const URI_UPDATE_HISTORY_DIALOG = "chrome://mozapps/content/update/history.xul";
|
24
|
+
const URI_BRAND_PROPERTIES = "chrome://branding/locale/brand.properties";
|
25
|
+
const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties";
|
26
|
+
const URI_UPDATE_NS = "http://www.mozilla.org/2005/app-update";
|
27
|
+
|
28
|
+
const KEY_APPDIR = "XCurProcD";
|
29
|
+
//@line 70 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
30
|
+
const KEY_UPDROOT = "UpdRootD";
|
31
|
+
const KEY_UAPPDATA = "UAppData";
|
32
|
+
//@line 73 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
33
|
+
|
34
|
+
const DIR_UPDATES = "updates";
|
35
|
+
const FILE_UPDATE_STATUS = "update.status";
|
36
|
+
const FILE_UPDATE_ARCHIVE = "update.mar";
|
37
|
+
const FILE_UPDATE_LOG = "update.log"
|
38
|
+
const FILE_UPDATES_DB = "updates.xml";
|
39
|
+
const FILE_UPDATE_ACTIVE = "active-update.xml";
|
40
|
+
const FILE_PERMS_TEST = "update.test";
|
41
|
+
const FILE_LAST_LOG = "last-update.log";
|
42
|
+
|
43
|
+
const MODE_RDONLY = 0x01;
|
44
|
+
const MODE_WRONLY = 0x02;
|
45
|
+
const MODE_CREATE = 0x08;
|
46
|
+
const MODE_APPEND = 0x10;
|
47
|
+
const MODE_TRUNCATE = 0x20;
|
48
|
+
|
49
|
+
const PERMS_FILE = 0644;
|
50
|
+
const PERMS_DIRECTORY = 0755;
|
51
|
+
|
52
|
+
const STATE_NONE = "null";
|
53
|
+
const STATE_DOWNLOADING = "downloading";
|
54
|
+
const STATE_PENDING = "pending";
|
55
|
+
const STATE_APPLYING = "applying";
|
56
|
+
const STATE_SUCCEEDED = "succeeded";
|
57
|
+
const STATE_DOWNLOAD_FAILED = "download-failed";
|
58
|
+
const STATE_FAILED = "failed";
|
59
|
+
|
60
|
+
// From updater/errors.h:
|
61
|
+
const WRITE_ERROR = 7;
|
62
|
+
|
63
|
+
const DOWNLOAD_CHUNK_SIZE = 300000; // bytes
|
64
|
+
const DOWNLOAD_BACKGROUND_INTERVAL = 600; // seconds
|
65
|
+
const DOWNLOAD_FOREGROUND_INTERVAL = 0;
|
66
|
+
|
67
|
+
// Values for the PREF_APP_UPDATE_INCOMPATIBLE_MODE pref. See documentation in
|
68
|
+
// code below.
|
69
|
+
const INCOMPATIBLE_MODE_NEWVERSIONS = 0;
|
70
|
+
const INCOMPATIBLE_MODE_NONEWVERSIONS = 1;
|
71
|
+
|
72
|
+
const POST_UPDATE_CONTRACTID = "@mozilla.org/updates/post-update;1";
|
73
|
+
|
74
|
+
const nsILocalFile = Components.interfaces.nsILocalFile;
|
75
|
+
const nsIUpdateService = Components.interfaces.nsIUpdateService;
|
76
|
+
const nsIUpdateItem = Components.interfaces.nsIUpdateItem;
|
77
|
+
const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString;
|
78
|
+
const nsIIncrementalDownload = Components.interfaces.nsIIncrementalDownload;
|
79
|
+
const nsIFileInputStream = Components.interfaces.nsIFileInputStream;
|
80
|
+
const nsIFileOutputStream = Components.interfaces.nsIFileOutputStream;
|
81
|
+
const nsICryptoHash = Components.interfaces.nsICryptoHash;
|
82
|
+
|
83
|
+
const Node = Components.interfaces.nsIDOMNode;
|
84
|
+
|
85
|
+
var gApp = null;
|
86
|
+
var gPref = null;
|
87
|
+
var gABI = null;
|
88
|
+
var gOSVersion = null;
|
89
|
+
var gConsole = null;
|
90
|
+
var gLogEnabled = { };
|
91
|
+
|
92
|
+
// shared code for suppressing bad cert dialogs
|
93
|
+
//@line 40 "/c/mozilla/toolkit/mozapps/update/src/../../shared/src/badCertHandler.js"
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Only allow built-in certs for HTTPS connections. See bug 340198.
|
97
|
+
*/
|
98
|
+
function checkCert(channel) {
|
99
|
+
if (!channel.originalURI.schemeIs("https")) // bypass
|
100
|
+
return;
|
101
|
+
|
102
|
+
const Ci = Components.interfaces;
|
103
|
+
var cert =
|
104
|
+
channel.securityInfo.QueryInterface(Ci.nsISSLStatusProvider).
|
105
|
+
SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
|
106
|
+
|
107
|
+
var issuer = cert.issuer;
|
108
|
+
while (issuer && !cert.equals(issuer)) {
|
109
|
+
cert = issuer;
|
110
|
+
issuer = cert.issuer;
|
111
|
+
}
|
112
|
+
|
113
|
+
if (!issuer || issuer.tokenName != "Builtin Object Token")
|
114
|
+
throw "cert issuer is not built-in";
|
115
|
+
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* This class implements nsIBadCertListener. It's job is to prevent "bad cert"
|
119
|
+
* security dialogs from being shown to the user. It is better to simply fail
|
120
|
+
* if the certificate is bad. See bug 304286.
|
121
|
+
*/
|
122
|
+
function BadCertHandler() {
|
123
|
+
}
|
124
|
+
BadCertHandler.prototype = {
|
125
|
+
|
126
|
+
// nsIBadCertListener
|
127
|
+
confirmUnknownIssuer: function(socketInfo, cert, certAddType) {
|
128
|
+
LOG("EM BadCertHandler: Unknown issuer");
|
129
|
+
return false;
|
130
|
+
},
|
131
|
+
|
132
|
+
confirmMismatchDomain: function(socketInfo, targetURL, cert) {
|
133
|
+
LOG("EM BadCertHandler: Mismatched domain");
|
134
|
+
return false;
|
135
|
+
},
|
136
|
+
|
137
|
+
confirmCertExpired: function(socketInfo, cert) {
|
138
|
+
LOG("EM BadCertHandler: Expired certificate");
|
139
|
+
return false;
|
140
|
+
},
|
141
|
+
|
142
|
+
notifyCrlNextupdate: function(socketInfo, targetURL, cert) {
|
143
|
+
},
|
144
|
+
|
145
|
+
// nsIChannelEventSink
|
146
|
+
onChannelRedirect: function(oldChannel, newChannel, flags) {
|
147
|
+
// make sure the certificate of the old channel checks out before we follow
|
148
|
+
// a redirect from it. See bug 340198.
|
149
|
+
checkCert(oldChannel);
|
150
|
+
},
|
151
|
+
|
152
|
+
// nsIInterfaceRequestor
|
153
|
+
getInterface: function(iid) {
|
154
|
+
if (iid.equals(Components.interfaces.nsIBadCertListener) ||
|
155
|
+
iid.equals(Components.interfaces.nsIChannelEventSink))
|
156
|
+
return this;
|
157
|
+
|
158
|
+
Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
|
159
|
+
return null;
|
160
|
+
},
|
161
|
+
|
162
|
+
// nsISupports
|
163
|
+
QueryInterface: function(iid) {
|
164
|
+
if (!iid.equals(Components.interfaces.nsIBadCertListener) &&
|
165
|
+
!iid.equals(Components.interfaces.nsIChannelEventSink) &&
|
166
|
+
!iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
|
167
|
+
!iid.equals(Components.interfaces.nsISupports))
|
168
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
169
|
+
return this;
|
170
|
+
}
|
171
|
+
};
|
172
|
+
//@line 134 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
173
|
+
|
174
|
+
/**
|
175
|
+
* Logs a string to the error console.
|
176
|
+
* @param string
|
177
|
+
* The string to write to the error console..
|
178
|
+
*/
|
179
|
+
function LOG(module, string) {
|
180
|
+
if (module in gLogEnabled) {
|
181
|
+
dump("*** " + module + ": " + string + "\n");
|
182
|
+
gConsole.logStringMessage(string);
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
/**
|
187
|
+
* Convert a string containing binary values to hex.
|
188
|
+
*/
|
189
|
+
function binaryToHex(input) {
|
190
|
+
var result = "";
|
191
|
+
for (var i = 0; i < input.length; ++i) {
|
192
|
+
var hex = input.charCodeAt(i).toString(16);
|
193
|
+
if (hex.length == 1)
|
194
|
+
hex = "0" + hex;
|
195
|
+
result += hex;
|
196
|
+
}
|
197
|
+
return result;
|
198
|
+
}
|
199
|
+
|
200
|
+
/**
|
201
|
+
* Gets a File URL spec for a nsIFile
|
202
|
+
* @param file
|
203
|
+
* The file to get a file URL spec to
|
204
|
+
* @returns The file URL spec to the file
|
205
|
+
*/
|
206
|
+
function getURLSpecFromFile(file) {
|
207
|
+
var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
|
208
|
+
.getService(Components.interfaces.nsIIOService);
|
209
|
+
var fph = ioServ.getProtocolHandler("file")
|
210
|
+
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
|
211
|
+
return fph.getURLSpecFromFile(file);
|
212
|
+
}
|
213
|
+
|
214
|
+
/**
|
215
|
+
* Gets the specified directory at the specified hierarchy under a
|
216
|
+
* Directory Service key.
|
217
|
+
* @param key
|
218
|
+
* The Directory Service Key to start from
|
219
|
+
* @param pathArray
|
220
|
+
* An array of path components to locate beneath the directory
|
221
|
+
* specified by |key|
|
222
|
+
* @return nsIFile object for the location specified. If the directory
|
223
|
+
* requested does not exist, it is created, along with any
|
224
|
+
* parent directories that need to be created.
|
225
|
+
*/
|
226
|
+
function getDir(key, pathArray) {
|
227
|
+
return getDirInternal(key, pathArray, true, false);
|
228
|
+
}
|
229
|
+
|
230
|
+
/**
|
231
|
+
* Gets the specified directory at the speciifed hierarchy under a
|
232
|
+
* Directory Service key.
|
233
|
+
* @param key
|
234
|
+
* The Directory Service Key to start from
|
235
|
+
* @param pathArray
|
236
|
+
* An array of path components to locate beneath the directory
|
237
|
+
* specified by |key|
|
238
|
+
* @return nsIFile object for the location specified. If the directory
|
239
|
+
* requested does not exist, it is NOT created.
|
240
|
+
*/
|
241
|
+
function getDirNoCreate(key, pathArray) {
|
242
|
+
return getDirInternal(key, pathArray, false, false);
|
243
|
+
}
|
244
|
+
|
245
|
+
/**
|
246
|
+
* Gets the specified directory at the specified hierarchy under the
|
247
|
+
* update root directory.
|
248
|
+
* @param pathArray
|
249
|
+
* An array of path components to locate beneath the directory
|
250
|
+
* specified by |key|
|
251
|
+
* @return nsIFile object for the location specified. If the directory
|
252
|
+
* requested does not exist, it is created, along with any
|
253
|
+
* parent directories that need to be created.
|
254
|
+
*/
|
255
|
+
function getUpdateDir(pathArray) {
|
256
|
+
return getDirInternal(KEY_APPDIR, pathArray, true, true);
|
257
|
+
}
|
258
|
+
|
259
|
+
/**
|
260
|
+
* Gets the specified directory at the speciifed hierarchy under a
|
261
|
+
* Directory Service key.
|
262
|
+
* @param key
|
263
|
+
* The Directory Service Key to start from
|
264
|
+
* @param pathArray
|
265
|
+
* An array of path components to locate beneath the directory
|
266
|
+
* specified by |key|
|
267
|
+
* @param shouldCreate
|
268
|
+
* true if the directory hierarchy specified in |pathArray|
|
269
|
+
* should be created if it does not exist,
|
270
|
+
* false otherwise.
|
271
|
+
* @param update
|
272
|
+
* true if finding the update directory,
|
273
|
+
* false otherwise.
|
274
|
+
* @return nsIFile object for the location specified.
|
275
|
+
*/
|
276
|
+
function getDirInternal(key, pathArray, shouldCreate, update) {
|
277
|
+
var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
|
278
|
+
.getService(Components.interfaces.nsIProperties);
|
279
|
+
var dir = fileLocator.get(key, Components.interfaces.nsIFile);
|
280
|
+
//@line 242 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
281
|
+
if (update) {
|
282
|
+
try {
|
283
|
+
dir = fileLocator.get(KEY_UPDROOT, Components.interfaces.nsIFile);
|
284
|
+
} catch (e) {
|
285
|
+
}
|
286
|
+
}
|
287
|
+
//@line 249 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
288
|
+
for (var i = 0; i < pathArray.length; ++i) {
|
289
|
+
dir.append(pathArray[i]);
|
290
|
+
if (shouldCreate && !dir.exists())
|
291
|
+
dir.create(nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
|
292
|
+
}
|
293
|
+
return dir;
|
294
|
+
}
|
295
|
+
|
296
|
+
/**
|
297
|
+
* Gets the file at the speciifed hierarchy under a Directory Service key.
|
298
|
+
* @param key
|
299
|
+
* The Directory Service Key to start from
|
300
|
+
* @param pathArray
|
301
|
+
* An array of path components to locate beneath the directory
|
302
|
+
* specified by |key|. The last item in this array must be the
|
303
|
+
* leaf name of a file.
|
304
|
+
* @return nsIFile object for the file specified. The file is NOT created
|
305
|
+
* if it does not exist, however all required directories along
|
306
|
+
* the way are.
|
307
|
+
*/
|
308
|
+
function getFile(key, pathArray) {
|
309
|
+
var file = getDir(key, pathArray.slice(0, -1));
|
310
|
+
file.append(pathArray[pathArray.length - 1]);
|
311
|
+
return file;
|
312
|
+
}
|
313
|
+
|
314
|
+
/**
|
315
|
+
* Gets the file at the speciifed hierarchy under the update root directory.
|
316
|
+
* @param pathArray
|
317
|
+
* An array of path components to locate beneath the directory
|
318
|
+
* specified by |key|. The last item in this array must be the
|
319
|
+
* leaf name of a file.
|
320
|
+
* @return nsIFile object for the file specified. The file is NOT created
|
321
|
+
* if it does not exist, however all required directories along
|
322
|
+
* the way are.
|
323
|
+
*/
|
324
|
+
function getUpdateFile(pathArray) {
|
325
|
+
var file = getUpdateDir(pathArray.slice(0, -1));
|
326
|
+
file.append(pathArray[pathArray.length - 1]);
|
327
|
+
return file;
|
328
|
+
}
|
329
|
+
|
330
|
+
/**
|
331
|
+
* Closes a Safe Output Stream
|
332
|
+
* @param fos
|
333
|
+
* The Safe Output Stream to close
|
334
|
+
*/
|
335
|
+
function closeSafeOutputStream(fos) {
|
336
|
+
if (fos instanceof Components.interfaces.nsISafeOutputStream) {
|
337
|
+
try {
|
338
|
+
fos.finish();
|
339
|
+
}
|
340
|
+
catch (e) {
|
341
|
+
fos.close();
|
342
|
+
}
|
343
|
+
}
|
344
|
+
else
|
345
|
+
fos.close();
|
346
|
+
}
|
347
|
+
|
348
|
+
/**
|
349
|
+
* Returns human readable status text from the updates.properties bundle
|
350
|
+
* based on an error code
|
351
|
+
* @param code
|
352
|
+
* The error code to look up human readable status text for
|
353
|
+
* @param defaultCode
|
354
|
+
* The default code to look up should human readable status text
|
355
|
+
* not exist for |code|
|
356
|
+
* @returns A human readable status text string
|
357
|
+
*/
|
358
|
+
function getStatusTextFromCode(code, defaultCode) {
|
359
|
+
var sbs =
|
360
|
+
Components.classes["@mozilla.org/intl/stringbundle;1"].
|
361
|
+
getService(Components.interfaces.nsIStringBundleService);
|
362
|
+
var updateBundle = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
363
|
+
var reason = updateBundle.GetStringFromName("checker_error-" + defaultCode);
|
364
|
+
try {
|
365
|
+
reason = updateBundle.GetStringFromName("checker_error-" + code);
|
366
|
+
LOG("General", "Transfer Error: " + reason + ", code: " + code);
|
367
|
+
}
|
368
|
+
catch (e) {
|
369
|
+
// Use the default reason
|
370
|
+
LOG("General", "Transfer Error: " + reason + ", code: " + defaultCode);
|
371
|
+
}
|
372
|
+
return reason;
|
373
|
+
}
|
374
|
+
|
375
|
+
/**
|
376
|
+
* Get the Active Updates directory
|
377
|
+
* @param key
|
378
|
+
* The Directory Service Key (optional).
|
379
|
+
* If used, don't search local appdata on Win32 and don't create dir.
|
380
|
+
* @returns The active updates directory, as a nsIFile object
|
381
|
+
*/
|
382
|
+
function getUpdatesDir(key) {
|
383
|
+
// Right now, we only support downloading one patch at a time, so we always
|
384
|
+
// use the same target directory.
|
385
|
+
var fileLocator =
|
386
|
+
Components.classes["@mozilla.org/file/directory_service;1"].
|
387
|
+
getService(Components.interfaces.nsIProperties);
|
388
|
+
var appDir;
|
389
|
+
if (key)
|
390
|
+
appDir = fileLocator.get(key, Components.interfaces.nsIFile);
|
391
|
+
else {
|
392
|
+
appDir = fileLocator.get(KEY_APPDIR, Components.interfaces.nsIFile);
|
393
|
+
//@line 355 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
394
|
+
try {
|
395
|
+
appDir = fileLocator.get(KEY_UPDROOT, Components.interfaces.nsIFile);
|
396
|
+
} catch (e) {
|
397
|
+
}
|
398
|
+
//@line 360 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
399
|
+
}
|
400
|
+
appDir.append(DIR_UPDATES);
|
401
|
+
appDir.append("0");
|
402
|
+
if (!appDir.exists() && !key)
|
403
|
+
appDir.create(nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
|
404
|
+
return appDir;
|
405
|
+
}
|
406
|
+
|
407
|
+
/**
|
408
|
+
* Reads the update state from the update.status file in the specified
|
409
|
+
* directory.
|
410
|
+
* @param dir
|
411
|
+
* The dir to look for an update.status file in
|
412
|
+
* @returns The status value of the update.
|
413
|
+
*/
|
414
|
+
function readStatusFile(dir) {
|
415
|
+
var statusFile = dir.clone();
|
416
|
+
statusFile.append(FILE_UPDATE_STATUS);
|
417
|
+
LOG("General", "Reading Status File: " + statusFile.path);
|
418
|
+
return readStringFromFile(statusFile) || STATE_NONE;
|
419
|
+
}
|
420
|
+
|
421
|
+
/**
|
422
|
+
* Writes the current update operation/state to a file in the patch
|
423
|
+
* directory, indicating to the patching system that operations need
|
424
|
+
* to be performed.
|
425
|
+
* @param dir
|
426
|
+
* The patch directory where the update.status file should be
|
427
|
+
* written.
|
428
|
+
* @param state
|
429
|
+
* The state value to write.
|
430
|
+
*/
|
431
|
+
function writeStatusFile(dir, state) {
|
432
|
+
var statusFile = dir.clone();
|
433
|
+
statusFile.append(FILE_UPDATE_STATUS);
|
434
|
+
writeStringToFile(statusFile, state);
|
435
|
+
}
|
436
|
+
|
437
|
+
/**
|
438
|
+
* Removes the Updates Directory
|
439
|
+
* @param key
|
440
|
+
* The Directory Service Key under which update directory resides
|
441
|
+
* (optional).
|
442
|
+
*/
|
443
|
+
function cleanUpUpdatesDir(key) {
|
444
|
+
// Bail out if we don't have appropriate permissions
|
445
|
+
var updateDir;
|
446
|
+
try {
|
447
|
+
updateDir = getUpdatesDir(key);
|
448
|
+
}
|
449
|
+
catch (e) {
|
450
|
+
return;
|
451
|
+
}
|
452
|
+
|
453
|
+
var e = updateDir.directoryEntries;
|
454
|
+
while (e.hasMoreElements()) {
|
455
|
+
var f = e.getNext().QueryInterface(Components.interfaces.nsIFile);
|
456
|
+
// Preserve the last update log file for debugging purposes
|
457
|
+
if (f.leafName == FILE_UPDATE_LOG) {
|
458
|
+
try {
|
459
|
+
var dir = f.parent.parent;
|
460
|
+
var logFile = dir.clone();
|
461
|
+
logFile.append(FILE_LAST_LOG);
|
462
|
+
if (logFile.exists())
|
463
|
+
logFile.remove(false);
|
464
|
+
f.copyTo(dir, FILE_LAST_LOG);
|
465
|
+
}
|
466
|
+
catch (e) {
|
467
|
+
LOG("General", "Failed to copy file: " + f.path);
|
468
|
+
}
|
469
|
+
}
|
470
|
+
// Now, recursively remove this file. The recusive removal is really
|
471
|
+
// only needed on Mac OSX because this directory will contain a copy of
|
472
|
+
// updater.app, which is itself a directory.
|
473
|
+
try {
|
474
|
+
f.remove(true);
|
475
|
+
}
|
476
|
+
catch (e) {
|
477
|
+
LOG("General", "Failed to remove file: " + f.path);
|
478
|
+
}
|
479
|
+
}
|
480
|
+
try {
|
481
|
+
updateDir.remove(false);
|
482
|
+
} catch (e) {
|
483
|
+
LOG("General", "Failed to remove update directory: " + updateDir.path +
|
484
|
+
" - This is almost always bad. Exception = " + e);
|
485
|
+
throw e;
|
486
|
+
}
|
487
|
+
}
|
488
|
+
|
489
|
+
/**
|
490
|
+
* Clean up updates list and the updates directory.
|
491
|
+
* @param key
|
492
|
+
* The Directory Service Key under which update directory resides
|
493
|
+
* (optional).
|
494
|
+
*/
|
495
|
+
function cleanupActiveUpdate(key) {
|
496
|
+
// Move the update from the Active Update list into the Past Updates list.
|
497
|
+
var um =
|
498
|
+
Components.classes["@mozilla.org/updates/update-manager;1"].
|
499
|
+
getService(Components.interfaces.nsIUpdateManager);
|
500
|
+
um.activeUpdate = null;
|
501
|
+
um.saveUpdates();
|
502
|
+
|
503
|
+
// Now trash the updates directory, since we're done with it
|
504
|
+
cleanUpUpdatesDir(key);
|
505
|
+
}
|
506
|
+
|
507
|
+
/**
|
508
|
+
* Gets a preference value, handling the case where there is no default.
|
509
|
+
* @param func
|
510
|
+
* The name of the preference function to call, on nsIPrefBranch
|
511
|
+
* @param preference
|
512
|
+
* The name of the preference
|
513
|
+
* @param defaultValue
|
514
|
+
* The default value to return in the event the preference has
|
515
|
+
* no setting
|
516
|
+
* @returns The value of the preference, or undefined if there was no
|
517
|
+
* user or default value.
|
518
|
+
*/
|
519
|
+
function getPref(func, preference, defaultValue) {
|
520
|
+
try {
|
521
|
+
return gPref[func](preference);
|
522
|
+
}
|
523
|
+
catch (e) {
|
524
|
+
}
|
525
|
+
return defaultValue;
|
526
|
+
}
|
527
|
+
|
528
|
+
/**
|
529
|
+
* Gets the current value of the locale. It's possible for this preference to
|
530
|
+
* be localized, so we have to do a little extra work here. Similar code
|
531
|
+
* exists in nsHttpHandler.cpp when building the UA string.
|
532
|
+
*/
|
533
|
+
function getLocale() {
|
534
|
+
try {
|
535
|
+
return gPref.getComplexValue(PREF_GENERAL_USERAGENT_LOCALE,
|
536
|
+
nsIPrefLocalizedString).data;
|
537
|
+
} catch (e) {}
|
538
|
+
|
539
|
+
return gPref.getCharPref(PREF_GENERAL_USERAGENT_LOCALE);
|
540
|
+
}
|
541
|
+
|
542
|
+
/**
|
543
|
+
* Read the update channel from defaults only. We do this to ensure that
|
544
|
+
* the channel is tightly coupled with the application and does not apply
|
545
|
+
* to other instances of the application that may use the same profile.
|
546
|
+
*/
|
547
|
+
function getUpdateChannel() {
|
548
|
+
var channel = "default";
|
549
|
+
var prefName;
|
550
|
+
var prefValue;
|
551
|
+
|
552
|
+
var defaults =
|
553
|
+
gPref.QueryInterface(Components.interfaces.nsIPrefService).
|
554
|
+
getDefaultBranch(null);
|
555
|
+
try {
|
556
|
+
channel = defaults.getCharPref(PREF_APP_UPDATE_CHANNEL);
|
557
|
+
} catch (e) {
|
558
|
+
// use default when pref not found
|
559
|
+
}
|
560
|
+
|
561
|
+
try {
|
562
|
+
var partners = gPref.getChildList(PREF_PARTNER_BRANCH, { });
|
563
|
+
if (partners.length) {
|
564
|
+
channel += "-cck";
|
565
|
+
partners.sort();
|
566
|
+
|
567
|
+
for each (prefName in partners) {
|
568
|
+
prefValue = gPref.getCharPref(prefName);
|
569
|
+
channel += "-" + prefValue;
|
570
|
+
}
|
571
|
+
}
|
572
|
+
}
|
573
|
+
catch (e) {
|
574
|
+
Components.utils.reportError(e);
|
575
|
+
}
|
576
|
+
|
577
|
+
return channel;
|
578
|
+
}
|
579
|
+
|
580
|
+
/**
|
581
|
+
* An enumeration of items in a JS array.
|
582
|
+
* @constructor
|
583
|
+
*/
|
584
|
+
function ArrayEnumerator(aItems) {
|
585
|
+
this._index = 0;
|
586
|
+
if (aItems) {
|
587
|
+
for (var i = 0; i < aItems.length; ++i) {
|
588
|
+
if (!aItems[i])
|
589
|
+
aItems.splice(i, 1);
|
590
|
+
}
|
591
|
+
}
|
592
|
+
this._contents = aItems;
|
593
|
+
}
|
594
|
+
|
595
|
+
ArrayEnumerator.prototype = {
|
596
|
+
_index: 0,
|
597
|
+
_contents: [],
|
598
|
+
|
599
|
+
hasMoreElements: function() {
|
600
|
+
return this._index < this._contents.length;
|
601
|
+
},
|
602
|
+
|
603
|
+
getNext: function() {
|
604
|
+
return this._contents[this._index++];
|
605
|
+
}
|
606
|
+
};
|
607
|
+
|
608
|
+
/**
|
609
|
+
* Trims a prefix from a string.
|
610
|
+
* @param string
|
611
|
+
* The source string
|
612
|
+
* @param prefix
|
613
|
+
* The prefix to remove.
|
614
|
+
* @returns The suffix (string - prefix)
|
615
|
+
*/
|
616
|
+
function stripPrefix(string, prefix) {
|
617
|
+
return string.substr(prefix.length);
|
618
|
+
}
|
619
|
+
|
620
|
+
/**
|
621
|
+
* Writes a string of text to a file. A newline will be appended to the data
|
622
|
+
* written to the file. This function only works with ASCII text.
|
623
|
+
*/
|
624
|
+
function writeStringToFile(file, text) {
|
625
|
+
var fos =
|
626
|
+
Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
|
627
|
+
createInstance(nsIFileOutputStream);
|
628
|
+
var modeFlags = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE;
|
629
|
+
if (!file.exists())
|
630
|
+
file.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
631
|
+
fos.init(file, modeFlags, PERMS_FILE, 0);
|
632
|
+
text += "\n";
|
633
|
+
fos.write(text, text.length);
|
634
|
+
closeSafeOutputStream(fos);
|
635
|
+
}
|
636
|
+
|
637
|
+
/**
|
638
|
+
* Reads a string of text from a file. A trailing newline will be removed
|
639
|
+
* before the result is returned. This function only works with ASCII text.
|
640
|
+
*/
|
641
|
+
function readStringFromFile(file) {
|
642
|
+
var fis =
|
643
|
+
Components.classes["@mozilla.org/network/file-input-stream;1"].
|
644
|
+
createInstance(nsIFileInputStream);
|
645
|
+
var modeFlags = MODE_RDONLY;
|
646
|
+
if (!file.exists())
|
647
|
+
return null;
|
648
|
+
fis.init(file, modeFlags, PERMS_FILE, 0);
|
649
|
+
var sis =
|
650
|
+
Components.classes["@mozilla.org/scriptableinputstream;1"].
|
651
|
+
createInstance(Components.interfaces.nsIScriptableInputStream);
|
652
|
+
sis.init(fis);
|
653
|
+
var text = sis.read(sis.available());
|
654
|
+
sis.close();
|
655
|
+
if (text[text.length - 1] == "\n")
|
656
|
+
text = text.slice(0, -1);
|
657
|
+
return text;
|
658
|
+
}
|
659
|
+
|
660
|
+
function getObserverService()
|
661
|
+
{
|
662
|
+
return Components.classes["@mozilla.org/observer-service;1"]
|
663
|
+
.getService(Components.interfaces.nsIObserverService);
|
664
|
+
}
|
665
|
+
|
666
|
+
/**
|
667
|
+
* Update Patch
|
668
|
+
* @param patch
|
669
|
+
* A <patch> element to initialize this object with
|
670
|
+
* @throws if patch has a size of 0
|
671
|
+
* @constructor
|
672
|
+
*/
|
673
|
+
function UpdatePatch(patch) {
|
674
|
+
this._properties = {};
|
675
|
+
for (var i = 0; i < patch.attributes.length; ++i) {
|
676
|
+
var attr = patch.attributes.item(i);
|
677
|
+
attr.QueryInterface(Components.interfaces.nsIDOMAttr);
|
678
|
+
switch (attr.name) {
|
679
|
+
case "selected":
|
680
|
+
this.selected = attr.value == "true";
|
681
|
+
break;
|
682
|
+
case "size":
|
683
|
+
if (0 == parseInt(attr.value)) {
|
684
|
+
LOG("UpdatePatch", "0-sized patch!");
|
685
|
+
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
|
686
|
+
}
|
687
|
+
default:
|
688
|
+
this[attr.name] = attr.value;
|
689
|
+
break;
|
690
|
+
};
|
691
|
+
}
|
692
|
+
}
|
693
|
+
UpdatePatch.prototype = {
|
694
|
+
/**
|
695
|
+
* See nsIUpdateService.idl
|
696
|
+
*/
|
697
|
+
serialize: function(updates) {
|
698
|
+
var patch = updates.createElementNS(URI_UPDATE_NS, "patch");
|
699
|
+
patch.setAttribute("type", this.type);
|
700
|
+
patch.setAttribute("URL", this.URL);
|
701
|
+
patch.setAttribute("hashFunction", this.hashFunction);
|
702
|
+
patch.setAttribute("hashValue", this.hashValue);
|
703
|
+
patch.setAttribute("size", this.size);
|
704
|
+
patch.setAttribute("selected", this.selected);
|
705
|
+
patch.setAttribute("state", this.state);
|
706
|
+
|
707
|
+
for (var p in this._properties) {
|
708
|
+
if (this._properties[p].present)
|
709
|
+
patch.setAttribute(p, this._properties[p].data);
|
710
|
+
}
|
711
|
+
|
712
|
+
return patch;
|
713
|
+
},
|
714
|
+
|
715
|
+
/**
|
716
|
+
* A hash of custom properties
|
717
|
+
*/
|
718
|
+
_properties: null,
|
719
|
+
|
720
|
+
/**
|
721
|
+
* See nsIWritablePropertyBag.idl
|
722
|
+
*/
|
723
|
+
setProperty: function(name, value) {
|
724
|
+
this._properties[name] = { data: value, present: true };
|
725
|
+
},
|
726
|
+
|
727
|
+
/**
|
728
|
+
* See nsIWritablePropertyBag.idl
|
729
|
+
*/
|
730
|
+
deleteProperty: function(name) {
|
731
|
+
if (name in this._properties)
|
732
|
+
this._properties[name].present = false;
|
733
|
+
else
|
734
|
+
throw Components.results.NS_ERROR_FAILURE;
|
735
|
+
},
|
736
|
+
|
737
|
+
/**
|
738
|
+
* See nsIPropertyBag.idl
|
739
|
+
*/
|
740
|
+
get enumerator() {
|
741
|
+
var properties = [];
|
742
|
+
for (var p in this._properties)
|
743
|
+
properties.push(this._properties[p].data);
|
744
|
+
return new ArrayEnumerator(properties);
|
745
|
+
},
|
746
|
+
|
747
|
+
/**
|
748
|
+
* See nsIPropertyBag.idl
|
749
|
+
*/
|
750
|
+
getProperty: function(name) {
|
751
|
+
if (name in this._properties &&
|
752
|
+
this._properties[name].present)
|
753
|
+
return this._properties[name].data;
|
754
|
+
throw Components.results.NS_ERROR_FAILURE;
|
755
|
+
},
|
756
|
+
|
757
|
+
/**
|
758
|
+
* Returns whether or not the update.status file for this patch exists at the
|
759
|
+
* appropriate location.
|
760
|
+
*/
|
761
|
+
get statusFileExists() {
|
762
|
+
var statusFile = getUpdatesDir();
|
763
|
+
statusFile.append(FILE_UPDATE_STATUS);
|
764
|
+
return statusFile.exists();
|
765
|
+
},
|
766
|
+
|
767
|
+
/**
|
768
|
+
* See nsIUpdateService.idl
|
769
|
+
*/
|
770
|
+
get state() {
|
771
|
+
if (!this.statusFileExists)
|
772
|
+
return STATE_NONE;
|
773
|
+
return this._properties.state;
|
774
|
+
},
|
775
|
+
set state(val) {
|
776
|
+
this._properties.state = val;
|
777
|
+
},
|
778
|
+
|
779
|
+
/**
|
780
|
+
* See nsISupports.idl
|
781
|
+
*/
|
782
|
+
QueryInterface: function(iid) {
|
783
|
+
if (!iid.equals(Components.interfaces.nsIUpdatePatch) &&
|
784
|
+
!iid.equals(Components.interfaces.nsIPropertyBag) &&
|
785
|
+
!iid.equals(Components.interfaces.nsIWritablePropertyBag) &&
|
786
|
+
!iid.equals(Components.interfaces.nsISupports))
|
787
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
788
|
+
return this;
|
789
|
+
}
|
790
|
+
};
|
791
|
+
|
792
|
+
/**
|
793
|
+
* Update
|
794
|
+
* Implements nsIUpdate
|
795
|
+
* @param update
|
796
|
+
* An <update> element to initialize this object with
|
797
|
+
* @throws if the update contains no patches
|
798
|
+
* @constructor
|
799
|
+
*/
|
800
|
+
function Update(update) {
|
801
|
+
this._properties = {};
|
802
|
+
this._patches = [];
|
803
|
+
this.installDate = 0;
|
804
|
+
this.isCompleteUpdate = false;
|
805
|
+
this.channel = "default";
|
806
|
+
|
807
|
+
// Null <update>, assume this is a message container and do no
|
808
|
+
// further initialization
|
809
|
+
if (!update)
|
810
|
+
return;
|
811
|
+
|
812
|
+
for (var i = 0; i < update.childNodes.length; ++i) {
|
813
|
+
var patchElement = update.childNodes.item(i);
|
814
|
+
if (patchElement.nodeType != Node.ELEMENT_NODE ||
|
815
|
+
patchElement.localName != "patch")
|
816
|
+
continue;
|
817
|
+
|
818
|
+
patchElement.QueryInterface(Components.interfaces.nsIDOMElement);
|
819
|
+
try {
|
820
|
+
var patch = new UpdatePatch(patchElement);
|
821
|
+
} catch (e) {
|
822
|
+
continue;
|
823
|
+
}
|
824
|
+
this._patches.push(patch);
|
825
|
+
}
|
826
|
+
|
827
|
+
if (0 == this._patches.length)
|
828
|
+
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
|
829
|
+
|
830
|
+
for (var i = 0; i < update.attributes.length; ++i) {
|
831
|
+
var attr = update.attributes.item(i);
|
832
|
+
attr.QueryInterface(Components.interfaces.nsIDOMAttr);
|
833
|
+
if (attr.name == "installDate" && attr.value)
|
834
|
+
this.installDate = parseInt(attr.value);
|
835
|
+
else if (attr.name == "isCompleteUpdate")
|
836
|
+
this.isCompleteUpdate = attr.value == "true";
|
837
|
+
else if (attr.name == "isSecurityUpdate")
|
838
|
+
this.isSecurityUpdate = attr.value == "true";
|
839
|
+
else if (attr.name == "detailsURL")
|
840
|
+
this._detailsURL = attr.value;
|
841
|
+
else if (attr.name == "channel")
|
842
|
+
this.channel = attr.value;
|
843
|
+
else
|
844
|
+
this[attr.name] = attr.value;
|
845
|
+
}
|
846
|
+
|
847
|
+
// The Update Name is either the string provided by the <update> element, or
|
848
|
+
// the string: "<App Name> <Update App Version>"
|
849
|
+
var name = "";
|
850
|
+
if (update.hasAttribute("name"))
|
851
|
+
name = update.getAttribute("name");
|
852
|
+
else {
|
853
|
+
var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
|
854
|
+
.getService(Components.interfaces.nsIStringBundleService);
|
855
|
+
var brandBundle = sbs.createBundle(URI_BRAND_PROPERTIES);
|
856
|
+
var updateBundle = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
857
|
+
var appName = brandBundle.GetStringFromName("brandShortName");
|
858
|
+
name = updateBundle.formatStringFromName("updateName",
|
859
|
+
[appName, this.version], 2);
|
860
|
+
}
|
861
|
+
this.name = name;
|
862
|
+
}
|
863
|
+
Update.prototype = {
|
864
|
+
/**
|
865
|
+
* See nsIUpdateService.idl
|
866
|
+
*/
|
867
|
+
get patchCount() {
|
868
|
+
return this._patches.length;
|
869
|
+
},
|
870
|
+
|
871
|
+
/**
|
872
|
+
* See nsIUpdateService.idl
|
873
|
+
*/
|
874
|
+
getPatchAt: function(index) {
|
875
|
+
return this._patches[index];
|
876
|
+
},
|
877
|
+
|
878
|
+
/**
|
879
|
+
* See nsIUpdateService.idl
|
880
|
+
*
|
881
|
+
* We use a copy of the state cached on this object in |_state| only when
|
882
|
+
* there is no selected patch, i.e. in the case when we could not load
|
883
|
+
* |.activeUpdate| from the update manager for some reason but still have
|
884
|
+
* the update.status file to work with.
|
885
|
+
*/
|
886
|
+
_state: "",
|
887
|
+
set state(state) {
|
888
|
+
if (this.selectedPatch)
|
889
|
+
this.selectedPatch.state = state;
|
890
|
+
this._state = state;
|
891
|
+
return state;
|
892
|
+
},
|
893
|
+
get state() {
|
894
|
+
if (this.selectedPatch)
|
895
|
+
return this.selectedPatch.state;
|
896
|
+
return this._state;
|
897
|
+
},
|
898
|
+
|
899
|
+
/**
|
900
|
+
* See nsIUpdateService.idl
|
901
|
+
*/
|
902
|
+
errorCode: 0,
|
903
|
+
|
904
|
+
/**
|
905
|
+
* See nsIUpdateService.idl
|
906
|
+
*/
|
907
|
+
get selectedPatch() {
|
908
|
+
for (var i = 0; i < this.patchCount; ++i) {
|
909
|
+
if (this._patches[i].selected)
|
910
|
+
return this._patches[i];
|
911
|
+
}
|
912
|
+
return null;
|
913
|
+
},
|
914
|
+
|
915
|
+
/**
|
916
|
+
* See nsIUpdateService.idl
|
917
|
+
*/
|
918
|
+
get detailsURL() {
|
919
|
+
if (!this._detailsURL) {
|
920
|
+
try {
|
921
|
+
// Try using a default details URL supplied by the distribution
|
922
|
+
// if the update XML does not supply one.
|
923
|
+
var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
|
924
|
+
.getService(Components.interfaces.nsIURLFormatter);
|
925
|
+
return formatter.formatURLPref(PREF_APP_UPDATE_URL_DETAILS);
|
926
|
+
}
|
927
|
+
catch (e) {
|
928
|
+
}
|
929
|
+
}
|
930
|
+
return this._detailsURL || "";
|
931
|
+
},
|
932
|
+
|
933
|
+
/**
|
934
|
+
* See nsIUpdateService.idl
|
935
|
+
*/
|
936
|
+
serialize: function(updates) {
|
937
|
+
var update = updates.createElementNS(URI_UPDATE_NS, "update");
|
938
|
+
update.setAttribute("type", this.type);
|
939
|
+
update.setAttribute("name", this.name);
|
940
|
+
update.setAttribute("version", this.version);
|
941
|
+
update.setAttribute("extensionVersion", this.extensionVersion);
|
942
|
+
update.setAttribute("detailsURL", this.detailsURL);
|
943
|
+
update.setAttribute("licenseURL", this.licenseURL);
|
944
|
+
update.setAttribute("serviceURL", this.serviceURL);
|
945
|
+
update.setAttribute("installDate", this.installDate);
|
946
|
+
update.setAttribute("statusText", this.statusText);
|
947
|
+
update.setAttribute("buildID", this.buildID);
|
948
|
+
update.setAttribute("isCompleteUpdate", this.isCompleteUpdate);
|
949
|
+
update.setAttribute("channel", this.channel);
|
950
|
+
updates.documentElement.appendChild(update);
|
951
|
+
|
952
|
+
for (var p in this._properties) {
|
953
|
+
if (this._properties[p].present)
|
954
|
+
update.setAttribute(p, this._properties[p].data);
|
955
|
+
}
|
956
|
+
|
957
|
+
for (var i = 0; i < this.patchCount; ++i)
|
958
|
+
update.appendChild(this.getPatchAt(i).serialize(updates));
|
959
|
+
|
960
|
+
return update;
|
961
|
+
},
|
962
|
+
|
963
|
+
/**
|
964
|
+
* A hash of custom properties
|
965
|
+
*/
|
966
|
+
_properties: null,
|
967
|
+
|
968
|
+
/**
|
969
|
+
* See nsIWritablePropertyBag.idl
|
970
|
+
*/
|
971
|
+
setProperty: function(name, value) {
|
972
|
+
this._properties[name] = { data: value, present: true };
|
973
|
+
},
|
974
|
+
|
975
|
+
/**
|
976
|
+
* See nsIWritablePropertyBag.idl
|
977
|
+
*/
|
978
|
+
deleteProperty: function(name) {
|
979
|
+
if (name in this._properties)
|
980
|
+
this._properties[name].present = false;
|
981
|
+
else
|
982
|
+
throw Components.results.NS_ERROR_FAILURE;
|
983
|
+
},
|
984
|
+
|
985
|
+
/**
|
986
|
+
* See nsIPropertyBag.idl
|
987
|
+
*/
|
988
|
+
get enumerator() {
|
989
|
+
var properties = [];
|
990
|
+
for (var p in this._properties)
|
991
|
+
properties.push(this._properties[p].data);
|
992
|
+
return new ArrayEnumerator(properties);
|
993
|
+
},
|
994
|
+
|
995
|
+
/**
|
996
|
+
* See nsIPropertyBag.idl
|
997
|
+
*/
|
998
|
+
getProperty: function(name) {
|
999
|
+
if (name in this._properties &&
|
1000
|
+
this._properties[name].present)
|
1001
|
+
return this._properties[name].data;
|
1002
|
+
throw Components.results.NS_ERROR_FAILURE;
|
1003
|
+
},
|
1004
|
+
|
1005
|
+
/**
|
1006
|
+
* See nsISupports.idl
|
1007
|
+
*/
|
1008
|
+
QueryInterface: function(iid) {
|
1009
|
+
if (!iid.equals(Components.interfaces.nsIUpdate_MOZILLA_1_8_BRANCH) &&
|
1010
|
+
!iid.equals(Components.interfaces.nsIUpdate) &&
|
1011
|
+
!iid.equals(Components.interfaces.nsIPropertyBag) &&
|
1012
|
+
!iid.equals(Components.interfaces.nsIWritablePropertyBag) &&
|
1013
|
+
!iid.equals(Components.interfaces.nsISupports))
|
1014
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
1015
|
+
return this;
|
1016
|
+
}
|
1017
|
+
};
|
1018
|
+
|
1019
|
+
/**
|
1020
|
+
* UpdateService
|
1021
|
+
* A Service for managing the discovery and installation of software updates.
|
1022
|
+
* @constructor
|
1023
|
+
*/
|
1024
|
+
function UpdateService() {
|
1025
|
+
gApp = Components.classes["@mozilla.org/xre/app-info;1"]
|
1026
|
+
.getService(Components.interfaces.nsIXULAppInfo)
|
1027
|
+
.QueryInterface(Components.interfaces.nsIXULRuntime);
|
1028
|
+
gPref = Components.classes["@mozilla.org/preferences-service;1"]
|
1029
|
+
.getService(Components.interfaces.nsIPrefBranch2);
|
1030
|
+
gConsole = Components.classes["@mozilla.org/consoleservice;1"]
|
1031
|
+
.getService(Components.interfaces.nsIConsoleService);
|
1032
|
+
|
1033
|
+
// Not all builds have a known ABI
|
1034
|
+
try {
|
1035
|
+
gABI = gApp.XPCOMABI;
|
1036
|
+
}
|
1037
|
+
catch (e) {
|
1038
|
+
LOG("UpdateService", "XPCOM ABI unknown: updates are not possible.");
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
try {
|
1042
|
+
var sysInfo =
|
1043
|
+
Components.classes["@mozilla.org/system-info;1"]
|
1044
|
+
.getService(Components.interfaces.nsIPropertyBag2);
|
1045
|
+
|
1046
|
+
gOSVersion = encodeURIComponent(sysInfo.getProperty("name") + " " +
|
1047
|
+
sysInfo.getProperty("version"));
|
1048
|
+
}
|
1049
|
+
catch (e) {
|
1050
|
+
LOG("UpdateService", "OS Version unknown: updates are not possible.");
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
//@line 1023 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
1054
|
+
|
1055
|
+
// Start the update timer only after a profile has been selected so that the
|
1056
|
+
// appropriate values for the update check are read from the user's profile.
|
1057
|
+
var os = getObserverService();
|
1058
|
+
|
1059
|
+
os.addObserver(this, "profile-after-change", false);
|
1060
|
+
|
1061
|
+
// Observe xpcom-shutdown to unhook pref branch observers above to avoid
|
1062
|
+
// shutdown leaks.
|
1063
|
+
os.addObserver(this, "xpcom-shutdown", false);
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
UpdateService.prototype = {
|
1067
|
+
/**
|
1068
|
+
* The downloader we are using to download updates. There is only ever one of
|
1069
|
+
* these.
|
1070
|
+
*/
|
1071
|
+
_downloader: null,
|
1072
|
+
|
1073
|
+
/**
|
1074
|
+
* Handle Observer Service notifications
|
1075
|
+
* @param subject
|
1076
|
+
* The subject of the notification
|
1077
|
+
* @param topic
|
1078
|
+
* The notification name
|
1079
|
+
* @param data
|
1080
|
+
* Additional data
|
1081
|
+
*/
|
1082
|
+
observe: function(subject, topic, data) {
|
1083
|
+
var os = getObserverService();
|
1084
|
+
|
1085
|
+
switch (topic) {
|
1086
|
+
case "profile-after-change":
|
1087
|
+
os.removeObserver(this, "profile-after-change");
|
1088
|
+
this._start();
|
1089
|
+
break;
|
1090
|
+
case "xpcom-shutdown":
|
1091
|
+
os.removeObserver(this, "xpcom-shutdown");
|
1092
|
+
|
1093
|
+
// Release Services
|
1094
|
+
gApp = null;
|
1095
|
+
gPref = null;
|
1096
|
+
gConsole = null;
|
1097
|
+
break;
|
1098
|
+
}
|
1099
|
+
},
|
1100
|
+
|
1101
|
+
/**
|
1102
|
+
* Start the Update Service
|
1103
|
+
*/
|
1104
|
+
_start: function() {
|
1105
|
+
// Start logging
|
1106
|
+
this._initLoggingPrefs();
|
1107
|
+
|
1108
|
+
// Clean up any extant updates
|
1109
|
+
this._postUpdateProcessing();
|
1110
|
+
|
1111
|
+
// Register a background update check timer
|
1112
|
+
var tm =
|
1113
|
+
Components.classes["@mozilla.org/updates/timer-manager;1"]
|
1114
|
+
.getService(Components.interfaces.nsIUpdateTimerManager);
|
1115
|
+
var interval = getPref("getIntPref", PREF_APP_UPDATE_INTERVAL, 86400);
|
1116
|
+
tm.registerTimer("background-update-timer", this, interval);
|
1117
|
+
|
1118
|
+
// Resume fetching...
|
1119
|
+
var um = Components.classes["@mozilla.org/updates/update-manager;1"]
|
1120
|
+
.getService(Components.interfaces.nsIUpdateManager);
|
1121
|
+
var activeUpdate = um.activeUpdate;
|
1122
|
+
if (activeUpdate) {
|
1123
|
+
var status = this.downloadUpdate(activeUpdate, true);
|
1124
|
+
if (status == STATE_NONE)
|
1125
|
+
cleanupActiveUpdate();
|
1126
|
+
}
|
1127
|
+
},
|
1128
|
+
|
1129
|
+
/**
|
1130
|
+
* Perform post-processing on updates lingering in the updates directory
|
1131
|
+
* from a previous browser session - either report install failures (and
|
1132
|
+
* optionally attempt to fetch a different version if appropriate) or
|
1133
|
+
* notify the user of install success.
|
1134
|
+
*/
|
1135
|
+
_postUpdateProcessing: function() {
|
1136
|
+
// Detect installation failures and notify
|
1137
|
+
|
1138
|
+
// Bail out if we don't have appropriate permissions
|
1139
|
+
if (!this.canUpdate)
|
1140
|
+
return;
|
1141
|
+
|
1142
|
+
var status = readStatusFile(getUpdatesDir());
|
1143
|
+
|
1144
|
+
// Make sure to cleanup after an update that failed for an unknown reason
|
1145
|
+
if (status == "null")
|
1146
|
+
status = null;
|
1147
|
+
|
1148
|
+
var updRootKey = null;
|
1149
|
+
//@line 1119 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
1150
|
+
function findPreviousUpdate(key) {
|
1151
|
+
var updateDir = getUpdatesDir(key);
|
1152
|
+
if (updateDir.exists()) {
|
1153
|
+
status = readStatusFile(updateDir);
|
1154
|
+
// Previous download should succeed. Otherwise, we will not be here!
|
1155
|
+
if (status == STATE_SUCCEEDED)
|
1156
|
+
updRootKey = key;
|
1157
|
+
else
|
1158
|
+
status = null;
|
1159
|
+
}
|
1160
|
+
}
|
1161
|
+
|
1162
|
+
// required when updating from Fx 2.0.0.1 to 2.0.0.3 (or later)
|
1163
|
+
// on Windows Vista.
|
1164
|
+
if (status == null)
|
1165
|
+
findPreviousUpdate(KEY_UAPPDATA);
|
1166
|
+
|
1167
|
+
// required to migrate from older versions.
|
1168
|
+
if (status == null)
|
1169
|
+
findPreviousUpdate(KEY_APPDIR);
|
1170
|
+
//@line 1140 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
1171
|
+
|
1172
|
+
if (status == STATE_DOWNLOADING) {
|
1173
|
+
LOG("UpdateService", "_postUpdateProcessing: Downloading patch, resuming...");
|
1174
|
+
}
|
1175
|
+
else if (status != null) {
|
1176
|
+
// null status means the update.status file is not present, because either:
|
1177
|
+
// 1) no update was performed, and so there's no UI to show
|
1178
|
+
// 2) an update was attempted but failed during checking, transfer or
|
1179
|
+
// verification, and was cleaned up at that point, and UI notifying of
|
1180
|
+
// that error was shown at that stage.
|
1181
|
+
var um =
|
1182
|
+
Components.classes["@mozilla.org/updates/update-manager;1"].
|
1183
|
+
getService(Components.interfaces.nsIUpdateManager);
|
1184
|
+
var prompter =
|
1185
|
+
Components.classes["@mozilla.org/updates/update-prompt;1"].
|
1186
|
+
createInstance(Components.interfaces.nsIUpdatePrompt);
|
1187
|
+
|
1188
|
+
var shouldCleanup = true;
|
1189
|
+
var update = um.activeUpdate;
|
1190
|
+
if (!update) {
|
1191
|
+
update = new Update(null);
|
1192
|
+
}
|
1193
|
+
update.state = status;
|
1194
|
+
var sbs =
|
1195
|
+
Components.classes["@mozilla.org/intl/stringbundle;1"].
|
1196
|
+
getService(Components.interfaces.nsIStringBundleService);
|
1197
|
+
var bundle = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
1198
|
+
if (status == STATE_SUCCEEDED) {
|
1199
|
+
update.statusText = bundle.GetStringFromName("installSuccess");
|
1200
|
+
|
1201
|
+
// Dig through the update history to find the patch that was just
|
1202
|
+
// installed and update its metadata.
|
1203
|
+
for (var i = 0; i < um.updateCount; ++i) {
|
1204
|
+
var umUpdate = um.getUpdateAt(i);
|
1205
|
+
if (umUpdate && umUpdate.version == update.version &&
|
1206
|
+
umUpdate.buildID == update.buildID) {
|
1207
|
+
umUpdate.statusText = update.statusText;
|
1208
|
+
break;
|
1209
|
+
}
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
LOG("UpdateService", "_postUpdateProcessing: Install Succeeded, Showing UI");
|
1213
|
+
prompter.showUpdateInstalled(update);
|
1214
|
+
//@line 1187 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
1215
|
+
// Perform platform-specific post-update processing.
|
1216
|
+
if (POST_UPDATE_CONTRACTID in Components.classes) {
|
1217
|
+
Components.classes[POST_UPDATE_CONTRACTID].
|
1218
|
+
createInstance(Components.interfaces.nsIRunnable).run();
|
1219
|
+
}
|
1220
|
+
//@line 1193 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
1221
|
+
|
1222
|
+
// Done with this update. Clean it up.
|
1223
|
+
cleanupActiveUpdate(updRootKey);
|
1224
|
+
}
|
1225
|
+
else {
|
1226
|
+
// If we hit an error, then the error code will be included in the
|
1227
|
+
// status string following a colon. If we had an I/O error, then we
|
1228
|
+
// assume that the patch is not invalid, and we restage the patch so
|
1229
|
+
// that it can be attempted again the next time we restart.
|
1230
|
+
var ary = status.split(": ");
|
1231
|
+
update.state = ary[0];
|
1232
|
+
if (update.state == STATE_FAILED && ary[1]) {
|
1233
|
+
update.errorCode = ary[1];
|
1234
|
+
if (update.errorCode == WRITE_ERROR) {
|
1235
|
+
prompter.showUpdateError(update);
|
1236
|
+
writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
|
1237
|
+
return;
|
1238
|
+
}
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
// Something went wrong with the patch application process.
|
1242
|
+
cleanupActiveUpdate();
|
1243
|
+
|
1244
|
+
update.statusText = bundle.GetStringFromName("patchApplyFailure");
|
1245
|
+
var oldType = update.selectedPatch ? update.selectedPatch.type
|
1246
|
+
: "complete";
|
1247
|
+
if (update.selectedPatch && oldType == "partial") {
|
1248
|
+
// Partial patch application failed, try downloading the complete
|
1249
|
+
// update in the background instead.
|
1250
|
+
LOG("UpdateService", "_postUpdateProcessing: Install of Partial Patch " +
|
1251
|
+
"failed, downloading Complete Patch and maybe showing UI");
|
1252
|
+
var status = this.downloadUpdate(update, true);
|
1253
|
+
if (status == STATE_NONE)
|
1254
|
+
cleanupActiveUpdate();
|
1255
|
+
}
|
1256
|
+
else {
|
1257
|
+
LOG("UpdateService", "_postUpdateProcessing: Install of Complete or " +
|
1258
|
+
"only patch failed. Showing error.");
|
1259
|
+
}
|
1260
|
+
update.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
|
1261
|
+
update.setProperty("patchingFailed", oldType);
|
1262
|
+
prompter.showUpdateError(update);
|
1263
|
+
}
|
1264
|
+
}
|
1265
|
+
else {
|
1266
|
+
LOG("UpdateService", "_postUpdateProcessing: No Status, No Update");
|
1267
|
+
}
|
1268
|
+
},
|
1269
|
+
|
1270
|
+
/**
|
1271
|
+
* Initialize Logging preferences, formatted like so:
|
1272
|
+
* app.update.log.<moduleName> = <true|false>
|
1273
|
+
*/
|
1274
|
+
_initLoggingPrefs: function() {
|
1275
|
+
try {
|
1276
|
+
var ps = Components.classes["@mozilla.org/preferences-service;1"]
|
1277
|
+
.getService(Components.interfaces.nsIPrefService);
|
1278
|
+
var logBranch = ps.getBranch(PREF_APP_UPDATE_LOG_BRANCH);
|
1279
|
+
var modules = logBranch.getChildList("", { value: 0 });
|
1280
|
+
|
1281
|
+
for (var i = 0; i < modules.length; ++i) {
|
1282
|
+
if (logBranch.prefHasUserValue(modules[i]))
|
1283
|
+
gLogEnabled[modules[i]] = logBranch.getBoolPref(modules[i]);
|
1284
|
+
}
|
1285
|
+
}
|
1286
|
+
catch (e) {
|
1287
|
+
}
|
1288
|
+
},
|
1289
|
+
|
1290
|
+
/**
|
1291
|
+
*
|
1292
|
+
*/
|
1293
|
+
_needsToPromptForUpdate: function(updates) {
|
1294
|
+
// First, check for Extension incompatibilities. These trump any preference
|
1295
|
+
// settings.
|
1296
|
+
var em = Components.classes["@mozilla.org/extensions/manager;1"]
|
1297
|
+
.getService(Components.interfaces.nsIExtensionManager);
|
1298
|
+
var incompatibleList = { };
|
1299
|
+
for (var i = 0; i < updates.length; ++i) {
|
1300
|
+
var count = {};
|
1301
|
+
em.getIncompatibleItemList(gApp.ID, updates[i].extensionVersion,
|
1302
|
+
nsIUpdateItem.TYPE_ADDON, false, count);
|
1303
|
+
if (count.value > 0)
|
1304
|
+
return true;
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
// Now, inspect user preferences.
|
1308
|
+
|
1309
|
+
// No prompt necessary, silently update...
|
1310
|
+
return false;
|
1311
|
+
},
|
1312
|
+
|
1313
|
+
/**
|
1314
|
+
* Notified when a timer fires
|
1315
|
+
* @param timer
|
1316
|
+
* The timer that fired
|
1317
|
+
*/
|
1318
|
+
notify: function(timer) {
|
1319
|
+
// If a download is in progress, then do nothing.
|
1320
|
+
if (this.isDownloading || this._downloader && this._downloader.patchIsStaged)
|
1321
|
+
return;
|
1322
|
+
|
1323
|
+
var self = this;
|
1324
|
+
var listener = {
|
1325
|
+
/**
|
1326
|
+
* See nsIUpdateService.idl
|
1327
|
+
*/
|
1328
|
+
onProgress: function(request, position, totalSize) {
|
1329
|
+
},
|
1330
|
+
|
1331
|
+
/**
|
1332
|
+
* See nsIUpdateService.idl
|
1333
|
+
*/
|
1334
|
+
onCheckComplete: function(request, updates, updateCount) {
|
1335
|
+
self._selectAndInstallUpdate(updates);
|
1336
|
+
},
|
1337
|
+
|
1338
|
+
/**
|
1339
|
+
* See nsIUpdateService.idl
|
1340
|
+
*/
|
1341
|
+
onError: function(request, update) {
|
1342
|
+
LOG("Checker", "Error during background update: " + update.statusText);
|
1343
|
+
},
|
1344
|
+
}
|
1345
|
+
this.backgroundChecker.checkForUpdates(listener, false);
|
1346
|
+
},
|
1347
|
+
|
1348
|
+
/**
|
1349
|
+
* Determine whether or not an update requires user confirmation before it
|
1350
|
+
* can be installed.
|
1351
|
+
* @param update
|
1352
|
+
* The update to be installed
|
1353
|
+
* @returns true if a prompt UI should be shown asking the user if they want
|
1354
|
+
* to install the update, false if the update should just be
|
1355
|
+
* silently downloaded and installed.
|
1356
|
+
*/
|
1357
|
+
_shouldPrompt: function(update) {
|
1358
|
+
// There are two possible outcomes here:
|
1359
|
+
// 1. download and install the update automatically
|
1360
|
+
// 2. alert the user about the presence of an update before doing anything
|
1361
|
+
//
|
1362
|
+
// The outcome we follow is determined as follows:
|
1363
|
+
//
|
1364
|
+
// Note: all Major updates require notification and confirmation
|
1365
|
+
//
|
1366
|
+
// Update Type Mode Incompatible Outcome
|
1367
|
+
// Major 0 Yes or No Notify and Confirm
|
1368
|
+
// Major 1 No Notify and Confirm
|
1369
|
+
// Major 1 Yes Notify and Confirm
|
1370
|
+
// Major 2 Yes or No Notify and Confirm
|
1371
|
+
// Minor 0 Yes or No Auto Install
|
1372
|
+
// Minor 1 No Auto Install
|
1373
|
+
// Minor 1 Yes Notify and Confirm
|
1374
|
+
// Minor 2 No Auto Install
|
1375
|
+
// Minor 2 Yes Notify and Confirm
|
1376
|
+
//
|
1377
|
+
// In addition, if there is a license associated with an update, regardless
|
1378
|
+
// of type it must be agreed to.
|
1379
|
+
//
|
1380
|
+
// If app.update.enabled is set to false, an update check is not performed
|
1381
|
+
// at all, and so none of the decision making above is entered into.
|
1382
|
+
//
|
1383
|
+
if (update.type == "major") {
|
1384
|
+
LOG("Checker", "_shouldPrompt: Prompting because it is a major update");
|
1385
|
+
return true;
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
update.QueryInterface(Components.interfaces.nsIPropertyBag);
|
1389
|
+
try {
|
1390
|
+
var licenseAccepted = update.getProperty("licenseAccepted") == "true";
|
1391
|
+
}
|
1392
|
+
catch (e) {
|
1393
|
+
licenseAccepted = false;
|
1394
|
+
}
|
1395
|
+
|
1396
|
+
var updateEnabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true);
|
1397
|
+
if (!updateEnabled) {
|
1398
|
+
LOG("Checker", "_shouldPrompt: Not prompting because update is " +
|
1399
|
+
"disabled");
|
1400
|
+
return false;
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
// User has turned off automatic download and install
|
1404
|
+
var autoEnabled = getPref("getBoolPref", PREF_APP_UPDATE_AUTO, true);
|
1405
|
+
if (!autoEnabled) {
|
1406
|
+
LOG("Checker", "_shouldPrompt: Prompting because auto install is disabled");
|
1407
|
+
return true;
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
switch (getPref("getIntPref", PREF_APP_UPDATE_MODE, 1)) {
|
1411
|
+
case 1:
|
1412
|
+
// Mode 1 is do not prompt only if there are no incompatibilities
|
1413
|
+
// releases
|
1414
|
+
LOG("Checker", "_shouldPrompt: Prompting if there are incompatibilities");
|
1415
|
+
return !isCompatible(update);
|
1416
|
+
case 2:
|
1417
|
+
// Mode 2 is do not prompt only if there are no incompatibilities
|
1418
|
+
LOG("Checker", "_shouldPrompt: Prompting if there are incompatibilities");
|
1419
|
+
return !isCompatible(update);
|
1420
|
+
}
|
1421
|
+
// Mode 0 is do not prompt regardless of incompatibilities
|
1422
|
+
LOG("Checker", "_shouldPrompt: Not prompting the user - they choose to " +
|
1423
|
+
"ignore incompatibilities");
|
1424
|
+
return false;
|
1425
|
+
},
|
1426
|
+
|
1427
|
+
/**
|
1428
|
+
* Determine which of the specified updates should be installed.
|
1429
|
+
* @param updates
|
1430
|
+
* An array of available updates
|
1431
|
+
*/
|
1432
|
+
selectUpdate: function(updates) {
|
1433
|
+
if (updates.length == 0)
|
1434
|
+
return null;
|
1435
|
+
|
1436
|
+
// Choose the newest of the available minor and major updates.
|
1437
|
+
var majorUpdate = null, minorUpdate = null;
|
1438
|
+
var newestMinor = updates[0], newestMajor = updates[0];
|
1439
|
+
|
1440
|
+
var vc = Components.classes["@mozilla.org/xpcom/version-comparator;1"]
|
1441
|
+
.getService(Components.interfaces.nsIVersionComparator);
|
1442
|
+
for (var i = 0; i < updates.length; ++i) {
|
1443
|
+
if (updates[i].type == "major" &&
|
1444
|
+
vc.compare(newestMajor.version, updates[i].version) <= 0)
|
1445
|
+
majorUpdate = newestMajor = updates[i];
|
1446
|
+
if (updates[i].type == "minor" &&
|
1447
|
+
vc.compare(newestMinor.version, updates[i].version) <= 0)
|
1448
|
+
minorUpdate = newestMinor = updates[i];
|
1449
|
+
}
|
1450
|
+
|
1451
|
+
// IMPORTANT
|
1452
|
+
// If there's a minor update, always try and fetch that one first,
|
1453
|
+
// otherwise use the newest major update.
|
1454
|
+
// selectUpdate() only returns one update.
|
1455
|
+
// if major were to trump minor, and we said "never" to the major
|
1456
|
+
// we'd never get the minor update, since selectUpdate()
|
1457
|
+
// would return the major update that the user said "never" to
|
1458
|
+
// (shadowing the important minor update with security fixes)
|
1459
|
+
return minorUpdate || majorUpdate;
|
1460
|
+
},
|
1461
|
+
|
1462
|
+
/**
|
1463
|
+
* Determine which of the specified updates should be installed and
|
1464
|
+
* begin the download/installation process, optionally prompting the
|
1465
|
+
* user for permission if required.
|
1466
|
+
* @param updates
|
1467
|
+
* An array of available updates
|
1468
|
+
*/
|
1469
|
+
_selectAndInstallUpdate: function(updates) {
|
1470
|
+
// Don't prompt if there's an active update - the user is already
|
1471
|
+
// aware and is downloading, or performed some user action to prevent
|
1472
|
+
// notification.
|
1473
|
+
var um = Components.classes["@mozilla.org/updates/update-manager;1"]
|
1474
|
+
.getService(Components.interfaces.nsIUpdateManager);
|
1475
|
+
if (um.activeUpdate)
|
1476
|
+
return;
|
1477
|
+
|
1478
|
+
var update = this.selectUpdate(updates, updates.length);
|
1479
|
+
if (!update)
|
1480
|
+
return;
|
1481
|
+
|
1482
|
+
// check if the user said "never" to this version
|
1483
|
+
// this check is done here, and not in selectUpdate() so that
|
1484
|
+
// the user can get an upgrade they said "never" to if they
|
1485
|
+
// manually do "Check for Updates..."
|
1486
|
+
// note, selectUpdate() only returns one update.
|
1487
|
+
// but in selectUpdate(), minor updates trump major updates
|
1488
|
+
// if major trumps minor, and we said "never" to the major
|
1489
|
+
// we'd never see the minor update.
|
1490
|
+
//
|
1491
|
+
// note, the never decision should only apply to major updates
|
1492
|
+
// see bug #350636 for a scenario where this could potentially
|
1493
|
+
// be an issue
|
1494
|
+
var neverPrefName = PREF_UPDATE_NEVER_BRANCH + update.version;
|
1495
|
+
var never = getPref("getBoolPref", neverPrefName, false);
|
1496
|
+
if (never && update.type == "major")
|
1497
|
+
return;
|
1498
|
+
|
1499
|
+
if (this._shouldPrompt(update))
|
1500
|
+
showPromptIfNoIncompatibilities(update);
|
1501
|
+
else {
|
1502
|
+
LOG("UpdateService", "_selectAndInstallUpdate: No need to show prompt, just download update");
|
1503
|
+
var status = this.downloadUpdate(update, true);
|
1504
|
+
if (status == STATE_NONE)
|
1505
|
+
cleanupActiveUpdate();
|
1506
|
+
}
|
1507
|
+
},
|
1508
|
+
|
1509
|
+
/**
|
1510
|
+
* The Checker used for background update checks.
|
1511
|
+
*/
|
1512
|
+
_backgroundChecker: null,
|
1513
|
+
|
1514
|
+
/**
|
1515
|
+
* See nsIUpdateService.idl
|
1516
|
+
*/
|
1517
|
+
get backgroundChecker() {
|
1518
|
+
if (!this._backgroundChecker)
|
1519
|
+
this._backgroundChecker = new Checker();
|
1520
|
+
return this._backgroundChecker;
|
1521
|
+
},
|
1522
|
+
|
1523
|
+
/**
|
1524
|
+
* See nsIUpdateService.idl
|
1525
|
+
*/
|
1526
|
+
get canUpdate() {
|
1527
|
+
try {
|
1528
|
+
var appDirFile = getUpdateFile([FILE_PERMS_TEST]);
|
1529
|
+
if (!appDirFile.exists()) {
|
1530
|
+
appDirFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
1531
|
+
appDirFile.remove(false);
|
1532
|
+
}
|
1533
|
+
var updateDir = getUpdatesDir();
|
1534
|
+
var upDirFile = updateDir.clone();
|
1535
|
+
upDirFile.append(FILE_PERMS_TEST);
|
1536
|
+
if (!upDirFile.exists()) {
|
1537
|
+
upDirFile.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
1538
|
+
upDirFile.remove(false);
|
1539
|
+
}
|
1540
|
+
}
|
1541
|
+
catch (e) {
|
1542
|
+
// No write privileges to install directory
|
1543
|
+
return false;
|
1544
|
+
}
|
1545
|
+
// If the administrator has locked the app update functionality
|
1546
|
+
// OFF - this is not just a user setting, so disable the manual
|
1547
|
+
// UI too.
|
1548
|
+
var enabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true);
|
1549
|
+
if (!enabled && gPref.prefIsLocked(PREF_APP_UPDATE_ENABLED))
|
1550
|
+
return false;
|
1551
|
+
|
1552
|
+
// If we don't know the binary platform we're updating, we can't update.
|
1553
|
+
if (!gABI)
|
1554
|
+
return false;
|
1555
|
+
|
1556
|
+
// If we don't know the OS version we're updating, we can't update.
|
1557
|
+
if (!gOSVersion)
|
1558
|
+
return false;
|
1559
|
+
|
1560
|
+
return true;
|
1561
|
+
},
|
1562
|
+
|
1563
|
+
/**
|
1564
|
+
* See nsIUpdateService.idl
|
1565
|
+
*/
|
1566
|
+
addDownloadListener: function(listener) {
|
1567
|
+
if (!this._downloader) {
|
1568
|
+
LOG("UpdateService", "addDownloadListener: no downloader!\n");
|
1569
|
+
return;
|
1570
|
+
}
|
1571
|
+
this._downloader.addDownloadListener(listener);
|
1572
|
+
},
|
1573
|
+
|
1574
|
+
/**
|
1575
|
+
* See nsIUpdateService.idl
|
1576
|
+
*/
|
1577
|
+
removeDownloadListener: function(listener) {
|
1578
|
+
if (!this._downloader) {
|
1579
|
+
LOG("UpdateService", "removeDownloadListener: no downloader!\n");
|
1580
|
+
return;
|
1581
|
+
}
|
1582
|
+
this._downloader.removeDownloadListener(listener);
|
1583
|
+
},
|
1584
|
+
|
1585
|
+
/**
|
1586
|
+
* See nsIUpdateService.idl
|
1587
|
+
*/
|
1588
|
+
downloadUpdate: function(update, background) {
|
1589
|
+
if (!update)
|
1590
|
+
throw Components.results.NS_ERROR_NULL_POINTER;
|
1591
|
+
if (this.isDownloading) {
|
1592
|
+
if (update.isCompleteUpdate == this._downloader.isCompleteUpdate &&
|
1593
|
+
background == this._downloader.background) {
|
1594
|
+
LOG("UpdateService", "no support for downloading more than one update at a time");
|
1595
|
+
return readStatusFile(getUpdatesDir());
|
1596
|
+
}
|
1597
|
+
this._downloader.cancel();
|
1598
|
+
}
|
1599
|
+
this._downloader = new Downloader(background);
|
1600
|
+
return this._downloader.downloadUpdate(update);
|
1601
|
+
},
|
1602
|
+
|
1603
|
+
/**
|
1604
|
+
* See nsIUpdateService.idl
|
1605
|
+
*/
|
1606
|
+
pauseDownload: function() {
|
1607
|
+
if (this.isDownloading)
|
1608
|
+
this._downloader.cancel();
|
1609
|
+
},
|
1610
|
+
|
1611
|
+
/**
|
1612
|
+
* See nsIUpdateService.idl
|
1613
|
+
*/
|
1614
|
+
get isDownloading() {
|
1615
|
+
return this._downloader && this._downloader.isBusy;
|
1616
|
+
},
|
1617
|
+
|
1618
|
+
/**
|
1619
|
+
* See nsISupports.idl
|
1620
|
+
*/
|
1621
|
+
QueryInterface: function(iid) {
|
1622
|
+
if (!iid.equals(Components.interfaces.nsIApplicationUpdateService) &&
|
1623
|
+
!iid.equals(Components.interfaces.nsITimerCallback) &&
|
1624
|
+
!iid.equals(Components.interfaces.nsIObserver) &&
|
1625
|
+
!iid.equals(Components.interfaces.nsISupports))
|
1626
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
1627
|
+
return this;
|
1628
|
+
}
|
1629
|
+
};
|
1630
|
+
|
1631
|
+
/**
|
1632
|
+
* A service to manage active and past updates.
|
1633
|
+
* @constructor
|
1634
|
+
*/
|
1635
|
+
function UpdateManager() {
|
1636
|
+
// Ensure the Active Update file is loaded
|
1637
|
+
var updates = this._loadXMLFileIntoArray(getUpdateFile([FILE_UPDATE_ACTIVE]));
|
1638
|
+
if (updates.length > 0)
|
1639
|
+
this._activeUpdate = updates[0];
|
1640
|
+
}
|
1641
|
+
UpdateManager.prototype = {
|
1642
|
+
/**
|
1643
|
+
* All previously downloaded and installed updates, as an array of nsIUpdate
|
1644
|
+
* objects.
|
1645
|
+
*/
|
1646
|
+
_updates: null,
|
1647
|
+
|
1648
|
+
/**
|
1649
|
+
* The current actively downloading/installing update, as a nsIUpdate object.
|
1650
|
+
*/
|
1651
|
+
_activeUpdate: null,
|
1652
|
+
|
1653
|
+
/**
|
1654
|
+
* Loads an updates.xml formatted file into an array of nsIUpdate items.
|
1655
|
+
* @param file
|
1656
|
+
* A nsIFile for the updates.xml file
|
1657
|
+
* @returns The array of nsIUpdate items held in the file.
|
1658
|
+
*/
|
1659
|
+
_loadXMLFileIntoArray: function(file) {
|
1660
|
+
if (!file.exists()) {
|
1661
|
+
LOG("UpdateManager", "_loadXMLFileIntoArray: XML File does not exist");
|
1662
|
+
return [];
|
1663
|
+
}
|
1664
|
+
|
1665
|
+
var result = [];
|
1666
|
+
var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
1667
|
+
.createInstance(Components.interfaces.nsIFileInputStream);
|
1668
|
+
fileStream.init(file, MODE_RDONLY, PERMS_FILE, 0);
|
1669
|
+
try {
|
1670
|
+
var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
|
1671
|
+
.createInstance(Components.interfaces.nsIDOMParser);
|
1672
|
+
var doc = parser.parseFromStream(fileStream, "UTF-8", fileStream.available(), "text/xml");
|
1673
|
+
|
1674
|
+
var updateCount = doc.documentElement.childNodes.length;
|
1675
|
+
for (var i = 0; i < updateCount; ++i) {
|
1676
|
+
var updateElement = doc.documentElement.childNodes.item(i);
|
1677
|
+
if (updateElement.nodeType != Node.ELEMENT_NODE ||
|
1678
|
+
updateElement.localName != "update")
|
1679
|
+
continue;
|
1680
|
+
|
1681
|
+
updateElement.QueryInterface(Components.interfaces.nsIDOMElement);
|
1682
|
+
try {
|
1683
|
+
var update = new Update(updateElement);
|
1684
|
+
} catch (e) {
|
1685
|
+
LOG("UpdateManager", "_loadXMLFileIntoArray: invalid update");
|
1686
|
+
continue;
|
1687
|
+
}
|
1688
|
+
result.push(new Update(updateElement));
|
1689
|
+
}
|
1690
|
+
}
|
1691
|
+
catch (e) {
|
1692
|
+
LOG("UpdateManager", "_loadXMLFileIntoArray: Error constructing update list " +
|
1693
|
+
e);
|
1694
|
+
}
|
1695
|
+
fileStream.close();
|
1696
|
+
return result;
|
1697
|
+
},
|
1698
|
+
|
1699
|
+
/**
|
1700
|
+
* Load the update manager, initializing state from state files.
|
1701
|
+
*/
|
1702
|
+
_ensureUpdates: function() {
|
1703
|
+
if (!this._updates) {
|
1704
|
+
this._updates = this._loadXMLFileIntoArray(getUpdateFile(
|
1705
|
+
[FILE_UPDATES_DB]));
|
1706
|
+
|
1707
|
+
// Make sure that any active update is part of our updates list
|
1708
|
+
var active = this.activeUpdate;
|
1709
|
+
if (active)
|
1710
|
+
this._addUpdate(active);
|
1711
|
+
}
|
1712
|
+
},
|
1713
|
+
|
1714
|
+
/**
|
1715
|
+
* See nsIUpdateService.idl
|
1716
|
+
*/
|
1717
|
+
getUpdateAt: function(index) {
|
1718
|
+
this._ensureUpdates();
|
1719
|
+
return this._updates[index];
|
1720
|
+
},
|
1721
|
+
|
1722
|
+
/**
|
1723
|
+
* See nsIUpdateService.idl
|
1724
|
+
*/
|
1725
|
+
get updateCount() {
|
1726
|
+
this._ensureUpdates();
|
1727
|
+
return this._updates.length;
|
1728
|
+
},
|
1729
|
+
|
1730
|
+
/**
|
1731
|
+
* See nsIUpdateService.idl
|
1732
|
+
*/
|
1733
|
+
get activeUpdate() {
|
1734
|
+
if (this._activeUpdate) {
|
1735
|
+
this._activeUpdate.QueryInterface(Components.interfaces.nsIUpdate_MOZILLA_1_8_BRANCH);
|
1736
|
+
if (this._activeUpdate.channel != getUpdateChannel()) {
|
1737
|
+
// User switched channels, clear out any old active updates and remove
|
1738
|
+
// partial downloads
|
1739
|
+
this._activeUpdate = null;
|
1740
|
+
|
1741
|
+
// Destroy the updates directory, since we're done with it.
|
1742
|
+
cleanUpUpdatesDir();
|
1743
|
+
}
|
1744
|
+
}
|
1745
|
+
return this._activeUpdate;
|
1746
|
+
},
|
1747
|
+
set activeUpdate(activeUpdate) {
|
1748
|
+
this._addUpdate(activeUpdate);
|
1749
|
+
this._activeUpdate = activeUpdate;
|
1750
|
+
if (!activeUpdate) {
|
1751
|
+
// If |activeUpdate| is null, we have updated both lists - the active list
|
1752
|
+
// and the history list, so we want to write both files.
|
1753
|
+
this.saveUpdates();
|
1754
|
+
}
|
1755
|
+
else
|
1756
|
+
this._writeUpdatesToXMLFile([this._activeUpdate],
|
1757
|
+
getUpdateFile([FILE_UPDATE_ACTIVE]));
|
1758
|
+
return activeUpdate;
|
1759
|
+
},
|
1760
|
+
|
1761
|
+
/**
|
1762
|
+
* Add an update to the Updates list. If the item already exists in the list,
|
1763
|
+
* replace the existing value with the new value.
|
1764
|
+
* @param update
|
1765
|
+
* The nsIUpdate object to add.
|
1766
|
+
*/
|
1767
|
+
_addUpdate: function(update) {
|
1768
|
+
if (!update)
|
1769
|
+
return;
|
1770
|
+
this._ensureUpdates();
|
1771
|
+
if (this._updates) {
|
1772
|
+
for (var i = 0; i < this._updates.length; ++i) {
|
1773
|
+
if (this._updates[i] &&
|
1774
|
+
this._updates[i].version == update.version &&
|
1775
|
+
this._updates[i].buildID == update.buildID) {
|
1776
|
+
// Replace the existing entry with the new value, updating
|
1777
|
+
// all metadata.
|
1778
|
+
this._updates[i] = update;
|
1779
|
+
return;
|
1780
|
+
}
|
1781
|
+
}
|
1782
|
+
}
|
1783
|
+
// Otherwise add it to the front of the list.
|
1784
|
+
if (update)
|
1785
|
+
this._updates = [update].concat(this._updates);
|
1786
|
+
},
|
1787
|
+
|
1788
|
+
/**
|
1789
|
+
* Serializes an array of updates to an XML file
|
1790
|
+
* @param updates
|
1791
|
+
* An array of nsIUpdate objects
|
1792
|
+
* @param file
|
1793
|
+
* The nsIFile object to serialize to
|
1794
|
+
*/
|
1795
|
+
_writeUpdatesToXMLFile: function(updates, file) {
|
1796
|
+
var fos = Components.classes["@mozilla.org/network/safe-file-output-stream;1"]
|
1797
|
+
.createInstance(Components.interfaces.nsIFileOutputStream);
|
1798
|
+
var modeFlags = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE;
|
1799
|
+
if (!file.exists())
|
1800
|
+
file.create(nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
1801
|
+
fos.init(file, modeFlags, PERMS_FILE, 0);
|
1802
|
+
|
1803
|
+
try {
|
1804
|
+
var parser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
|
1805
|
+
.createInstance(Components.interfaces.nsIDOMParser);
|
1806
|
+
const EMPTY_UPDATES_DOCUMENT = "<?xml version=\"1.0\"?><updates xmlns=\"http://www.mozilla.org/2005/app-update\"></updates>";
|
1807
|
+
var doc = parser.parseFromString(EMPTY_UPDATES_DOCUMENT, "text/xml");
|
1808
|
+
|
1809
|
+
for (var i = 0; i < updates.length; ++i) {
|
1810
|
+
if (updates[i])
|
1811
|
+
doc.documentElement.appendChild(updates[i].serialize(doc));
|
1812
|
+
}
|
1813
|
+
|
1814
|
+
var serializer = Components.classes["@mozilla.org/xmlextras/xmlserializer;1"]
|
1815
|
+
.createInstance(Components.interfaces.nsIDOMSerializer);
|
1816
|
+
serializer.serializeToStream(doc.documentElement, fos, null);
|
1817
|
+
}
|
1818
|
+
catch (e) {
|
1819
|
+
}
|
1820
|
+
|
1821
|
+
closeSafeOutputStream(fos);
|
1822
|
+
},
|
1823
|
+
|
1824
|
+
/**
|
1825
|
+
* See nsIUpdateService.idl
|
1826
|
+
*/
|
1827
|
+
saveUpdates: function() {
|
1828
|
+
this._writeUpdatesToXMLFile([this._activeUpdate],
|
1829
|
+
getUpdateFile([FILE_UPDATE_ACTIVE]));
|
1830
|
+
if (this._updates) {
|
1831
|
+
this._writeUpdatesToXMLFile(this._updates,
|
1832
|
+
getUpdateFile([FILE_UPDATES_DB]));
|
1833
|
+
}
|
1834
|
+
},
|
1835
|
+
|
1836
|
+
/**
|
1837
|
+
* See nsISupports.idl
|
1838
|
+
*/
|
1839
|
+
QueryInterface: function(iid) {
|
1840
|
+
if (!iid.equals(Components.interfaces.nsIUpdateManager) &&
|
1841
|
+
!iid.equals(Components.interfaces.nsISupports))
|
1842
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
1843
|
+
return this;
|
1844
|
+
}
|
1845
|
+
};
|
1846
|
+
|
1847
|
+
|
1848
|
+
/**
|
1849
|
+
* Checker
|
1850
|
+
* Checks for new Updates
|
1851
|
+
* @constructor
|
1852
|
+
*/
|
1853
|
+
function Checker() {
|
1854
|
+
}
|
1855
|
+
Checker.prototype = {
|
1856
|
+
/**
|
1857
|
+
* The XMLHttpRequest object that performs the connection.
|
1858
|
+
*/
|
1859
|
+
_request : null,
|
1860
|
+
|
1861
|
+
/**
|
1862
|
+
* The nsIUpdateCheckListener callback
|
1863
|
+
*/
|
1864
|
+
_callback : null,
|
1865
|
+
|
1866
|
+
/**
|
1867
|
+
* The URL of the update service XML file to connect to that contains details
|
1868
|
+
* about available updates.
|
1869
|
+
*/
|
1870
|
+
get updateURL() {
|
1871
|
+
var defaults =
|
1872
|
+
gPref.QueryInterface(Components.interfaces.nsIPrefService).
|
1873
|
+
getDefaultBranch(null);
|
1874
|
+
|
1875
|
+
// Use the override URL if specified.
|
1876
|
+
var url = getPref("getCharPref", PREF_APP_UPDATE_URL_OVERRIDE, null);
|
1877
|
+
|
1878
|
+
// Otherwise, construct the update URL from component parts.
|
1879
|
+
if (!url) {
|
1880
|
+
try {
|
1881
|
+
url = defaults.getCharPref(PREF_APP_UPDATE_URL);
|
1882
|
+
} catch (e) {
|
1883
|
+
}
|
1884
|
+
}
|
1885
|
+
|
1886
|
+
if (!url || url == "") {
|
1887
|
+
LOG("Checker", "Update URL not defined");
|
1888
|
+
return null;
|
1889
|
+
}
|
1890
|
+
|
1891
|
+
url = url.replace(/%PRODUCT%/g, gApp.name);
|
1892
|
+
url = url.replace(/%VERSION%/g, gApp.version);
|
1893
|
+
url = url.replace(/%BUILD_ID%/g, gApp.appBuildID);
|
1894
|
+
url = url.replace(/%BUILD_TARGET%/g, gApp.OS + "_" + gABI);
|
1895
|
+
url = url.replace(/%OS_VERSION%/g, gOSVersion);
|
1896
|
+
url = url.replace(/%LOCALE%/g, getLocale());
|
1897
|
+
url = url.replace(/%CHANNEL%/g, getUpdateChannel());
|
1898
|
+
url = url.replace(/\+/g, "%2B");
|
1899
|
+
|
1900
|
+
LOG("Checker", "update url: " + url);
|
1901
|
+
return url;
|
1902
|
+
},
|
1903
|
+
|
1904
|
+
/**
|
1905
|
+
* See nsIUpdateService.idl
|
1906
|
+
*/
|
1907
|
+
checkForUpdates: function(listener, force) {
|
1908
|
+
if (!listener)
|
1909
|
+
throw Components.results.NS_ERROR_NULL_POINTER;
|
1910
|
+
|
1911
|
+
if (!this.updateURL || (!this.enabled && !force))
|
1912
|
+
return;
|
1913
|
+
|
1914
|
+
this._request =
|
1915
|
+
Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
1916
|
+
createInstance(Components.interfaces.nsIXMLHttpRequest);
|
1917
|
+
this._request.open("GET", this.updateURL, true);
|
1918
|
+
this._request.channel.notificationCallbacks = new BadCertHandler();
|
1919
|
+
this._request.overrideMimeType("text/xml");
|
1920
|
+
this._request.setRequestHeader("Cache-Control", "no-cache");
|
1921
|
+
|
1922
|
+
var self = this;
|
1923
|
+
this._request.onerror = function(event) { self.onError(event); };
|
1924
|
+
this._request.onload = function(event) { self.onLoad(event); };
|
1925
|
+
this._request.onprogress = function(event) { self.onProgress(event); };
|
1926
|
+
|
1927
|
+
LOG("Checker", "checkForUpdates: sending request to " + this.updateURL);
|
1928
|
+
this._request.send(null);
|
1929
|
+
|
1930
|
+
this._callback = listener;
|
1931
|
+
},
|
1932
|
+
|
1933
|
+
/**
|
1934
|
+
* When progress associated with the XMLHttpRequest is received.
|
1935
|
+
* @param event
|
1936
|
+
* The nsIDOMLSProgressEvent for the load.
|
1937
|
+
*/
|
1938
|
+
onProgress: function(event) {
|
1939
|
+
LOG("Checker", "onProgress: " + event.position + "/" + event.totalSize);
|
1940
|
+
this._callback.onProgress(event.target, event.position, event.totalSize);
|
1941
|
+
},
|
1942
|
+
|
1943
|
+
/**
|
1944
|
+
* Returns an array of nsIUpdate objects discovered by the update check.
|
1945
|
+
*/
|
1946
|
+
get _updates() {
|
1947
|
+
var updatesElement = this._request.responseXML.documentElement;
|
1948
|
+
if (!updatesElement) {
|
1949
|
+
LOG("Checker", "get_updates: empty updates document?!");
|
1950
|
+
return [];
|
1951
|
+
}
|
1952
|
+
|
1953
|
+
if (updatesElement.nodeName != "updates") {
|
1954
|
+
LOG("Checker", "get_updates: unexpected node name!");
|
1955
|
+
throw "";
|
1956
|
+
}
|
1957
|
+
|
1958
|
+
var updates = [];
|
1959
|
+
for (var i = 0; i < updatesElement.childNodes.length; ++i) {
|
1960
|
+
var updateElement = updatesElement.childNodes.item(i);
|
1961
|
+
if (updateElement.nodeType != Node.ELEMENT_NODE ||
|
1962
|
+
updateElement.localName != "update")
|
1963
|
+
continue;
|
1964
|
+
|
1965
|
+
updateElement.QueryInterface(Components.interfaces.nsIDOMElement);
|
1966
|
+
try {
|
1967
|
+
var update = new Update(updateElement);
|
1968
|
+
} catch (e) {
|
1969
|
+
LOG("Checker", "Invalid <update/>, ignoring...");
|
1970
|
+
continue;
|
1971
|
+
}
|
1972
|
+
update.serviceURL = this.updateURL;
|
1973
|
+
update.channel = getUpdateChannel();
|
1974
|
+
updates.push(update);
|
1975
|
+
}
|
1976
|
+
|
1977
|
+
return updates;
|
1978
|
+
},
|
1979
|
+
|
1980
|
+
/**
|
1981
|
+
* The XMLHttpRequest succeeded and the document was loaded.
|
1982
|
+
* @param event
|
1983
|
+
* The nsIDOMLSEvent for the load
|
1984
|
+
*/
|
1985
|
+
onLoad: function(event) {
|
1986
|
+
LOG("Checker", "onLoad: request completed downloading document");
|
1987
|
+
|
1988
|
+
try {
|
1989
|
+
checkCert(this._request.channel);
|
1990
|
+
|
1991
|
+
// Analyze the resulting DOM and determine the set of updates to install
|
1992
|
+
var updates = this._updates;
|
1993
|
+
|
1994
|
+
LOG("Checker", "Updates available: " + updates.length);
|
1995
|
+
|
1996
|
+
// ... and tell the Update Service about what we discovered.
|
1997
|
+
this._callback.onCheckComplete(event.target, updates, updates.length);
|
1998
|
+
}
|
1999
|
+
catch (e) {
|
2000
|
+
LOG("Checker", "There was a problem with the update service URL specified, " +
|
2001
|
+
"either the XML file was malformed or it does not exist at the location " +
|
2002
|
+
"specified. Exception: " + e);
|
2003
|
+
var update = new Update(null);
|
2004
|
+
update.statusText = getStatusTextFromCode(404, 404);
|
2005
|
+
this._callback.onError(event.target, update);
|
2006
|
+
}
|
2007
|
+
|
2008
|
+
this._request = null;
|
2009
|
+
},
|
2010
|
+
|
2011
|
+
/**
|
2012
|
+
* There was an error of some kind during the XMLHttpRequest
|
2013
|
+
* @param event
|
2014
|
+
* The nsIDOMLSEvent for the load
|
2015
|
+
*/
|
2016
|
+
onError: function(event) {
|
2017
|
+
LOG("Checker", "onError: error during load");
|
2018
|
+
|
2019
|
+
var request = event.target;
|
2020
|
+
try {
|
2021
|
+
var status = request.status;
|
2022
|
+
}
|
2023
|
+
catch (e) {
|
2024
|
+
var req = request.channel.QueryInterface(Components.interfaces.nsIRequest);
|
2025
|
+
status = req.status;
|
2026
|
+
}
|
2027
|
+
|
2028
|
+
// If we can't find an error string specific to this status code,
|
2029
|
+
// just use the 200 message from above, which means everything
|
2030
|
+
// "looks" fine but there was probably an XML error or a bogus file.
|
2031
|
+
var update = new Update(null);
|
2032
|
+
update.statusText = getStatusTextFromCode(status, 200);
|
2033
|
+
this._callback.onError(request, update);
|
2034
|
+
|
2035
|
+
this._request = null;
|
2036
|
+
},
|
2037
|
+
|
2038
|
+
/**
|
2039
|
+
* Whether or not we are allowed to do update checking.
|
2040
|
+
*/
|
2041
|
+
_enabled: true,
|
2042
|
+
|
2043
|
+
/**
|
2044
|
+
* See nsIUpdateService.idl
|
2045
|
+
*/
|
2046
|
+
get enabled() {
|
2047
|
+
var aus =
|
2048
|
+
Components.classes["@mozilla.org/updates/update-service;1"].
|
2049
|
+
getService(Components.interfaces.nsIApplicationUpdateService);
|
2050
|
+
var enabled = getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true) &&
|
2051
|
+
aus.canUpdate && this._enabled;
|
2052
|
+
return enabled;
|
2053
|
+
},
|
2054
|
+
|
2055
|
+
/**
|
2056
|
+
* See nsIUpdateService.idl
|
2057
|
+
*/
|
2058
|
+
stopChecking: function(duration) {
|
2059
|
+
// Always stop the current check
|
2060
|
+
if (this._request)
|
2061
|
+
this._request.abort();
|
2062
|
+
|
2063
|
+
const nsIUpdateChecker = Components.interfaces.nsIUpdateChecker;
|
2064
|
+
switch (duration) {
|
2065
|
+
case nsIUpdateChecker.CURRENT_SESSION:
|
2066
|
+
this._enabled = false;
|
2067
|
+
break;
|
2068
|
+
case nsIUpdateChecker.ANY_CHECKS:
|
2069
|
+
this._enabled = false;
|
2070
|
+
gPref.setBoolPref(PREF_APP_UPDATE_ENABLED, this._enabled);
|
2071
|
+
break;
|
2072
|
+
}
|
2073
|
+
},
|
2074
|
+
|
2075
|
+
/**
|
2076
|
+
* See nsISupports.idl
|
2077
|
+
*/
|
2078
|
+
QueryInterface: function(iid) {
|
2079
|
+
if (!iid.equals(Components.interfaces.nsIUpdateChecker) &&
|
2080
|
+
!iid.equals(Components.interfaces.nsISupports))
|
2081
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
2082
|
+
return this;
|
2083
|
+
}
|
2084
|
+
};
|
2085
|
+
|
2086
|
+
/**
|
2087
|
+
* Manages the download of updates
|
2088
|
+
* @param background
|
2089
|
+
* Whether or not this downloader is operating in background
|
2090
|
+
* update mode.
|
2091
|
+
* @constructor
|
2092
|
+
*/
|
2093
|
+
function Downloader(background) {
|
2094
|
+
this.background = background;
|
2095
|
+
}
|
2096
|
+
Downloader.prototype = {
|
2097
|
+
/**
|
2098
|
+
* The nsIUpdatePatch that we are downloading
|
2099
|
+
*/
|
2100
|
+
_patch: null,
|
2101
|
+
|
2102
|
+
/**
|
2103
|
+
* The nsIUpdate that we are downloading
|
2104
|
+
*/
|
2105
|
+
_update: null,
|
2106
|
+
|
2107
|
+
/**
|
2108
|
+
* The nsIIncrementalDownload object handling the download
|
2109
|
+
*/
|
2110
|
+
_request: null,
|
2111
|
+
|
2112
|
+
/**
|
2113
|
+
* Whether or not the update being downloaded is a complete replacement of
|
2114
|
+
* the user's existing installation or a patch representing the difference
|
2115
|
+
* between the new version and the previous version.
|
2116
|
+
*/
|
2117
|
+
isCompleteUpdate: null,
|
2118
|
+
|
2119
|
+
/**
|
2120
|
+
* Cancels the active download.
|
2121
|
+
*/
|
2122
|
+
cancel: function() {
|
2123
|
+
if (this._request &&
|
2124
|
+
this._request instanceof Components.interfaces.nsIRequest) {
|
2125
|
+
const NS_BINDING_ABORTED = 0x804b0002;
|
2126
|
+
this._request.cancel(NS_BINDING_ABORTED);
|
2127
|
+
}
|
2128
|
+
},
|
2129
|
+
|
2130
|
+
/**
|
2131
|
+
* Whether or not a patch has been downloaded and staged for installation.
|
2132
|
+
*/
|
2133
|
+
get patchIsStaged() {
|
2134
|
+
return readStatusFile(getUpdatesDir()) == STATE_PENDING;
|
2135
|
+
},
|
2136
|
+
|
2137
|
+
/**
|
2138
|
+
* Verify the downloaded file. We assume that the download is complete at
|
2139
|
+
* this point.
|
2140
|
+
*/
|
2141
|
+
_verifyDownload: function() {
|
2142
|
+
if (!this._request)
|
2143
|
+
return false;
|
2144
|
+
|
2145
|
+
var destination = this._request.destination;
|
2146
|
+
|
2147
|
+
// Ensure that the file size matches the expected file size.
|
2148
|
+
if (destination.fileSize != this._patch.size)
|
2149
|
+
return false;
|
2150
|
+
|
2151
|
+
var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
|
2152
|
+
createInstance(nsIFileInputStream);
|
2153
|
+
fileStream.init(destination, MODE_RDONLY, PERMS_FILE, 0);
|
2154
|
+
|
2155
|
+
try {
|
2156
|
+
var hash = Components.classes["@mozilla.org/security/hash;1"].
|
2157
|
+
createInstance(nsICryptoHash);
|
2158
|
+
var hashFunction = nsICryptoHash[this._patch.hashFunction.toUpperCase()];
|
2159
|
+
if (hashFunction == undefined)
|
2160
|
+
throw Components.results.NS_ERROR_UNEXPECTED;
|
2161
|
+
hash.init(hashFunction);
|
2162
|
+
hash.updateFromStream(fileStream, -1);
|
2163
|
+
// NOTE: For now, we assume that the format of _patch.hashValue is hex
|
2164
|
+
// encoded binary (such as what is typically output by programs like
|
2165
|
+
// sha1sum). In the future, this may change to base64 depending on how
|
2166
|
+
// we choose to compute these hashes.
|
2167
|
+
digest = binaryToHex(hash.finish(false));
|
2168
|
+
} catch (e) {
|
2169
|
+
LOG("Downloader", "failed to compute hash of downloaded update archive");
|
2170
|
+
digest = "";
|
2171
|
+
}
|
2172
|
+
|
2173
|
+
fileStream.close();
|
2174
|
+
|
2175
|
+
return digest == this._patch.hashValue.toLowerCase();
|
2176
|
+
},
|
2177
|
+
|
2178
|
+
/**
|
2179
|
+
* Select the patch to use given the current state of updateDir and the given
|
2180
|
+
* set of update patches.
|
2181
|
+
* @param update
|
2182
|
+
* A nsIUpdate object to select a patch from
|
2183
|
+
* @param updateDir
|
2184
|
+
* A nsIFile representing the update directory
|
2185
|
+
* @returns A nsIUpdatePatch object to download
|
2186
|
+
*/
|
2187
|
+
_selectPatch: function(update, updateDir) {
|
2188
|
+
// Given an update to download, we will always try to download the patch
|
2189
|
+
// for a partial update over the patch for a full update.
|
2190
|
+
|
2191
|
+
/**
|
2192
|
+
* Return the first UpdatePatch with the given type.
|
2193
|
+
* @param type
|
2194
|
+
* The type of the patch ("complete" or "partial")
|
2195
|
+
* @returns A nsIUpdatePatch object matching the type specified
|
2196
|
+
*/
|
2197
|
+
function getPatchOfType(type) {
|
2198
|
+
for (var i = 0; i < update.patchCount; ++i) {
|
2199
|
+
var patch = update.getPatchAt(i);
|
2200
|
+
if (patch && patch.type == type)
|
2201
|
+
return patch;
|
2202
|
+
}
|
2203
|
+
return null;
|
2204
|
+
}
|
2205
|
+
|
2206
|
+
// Look to see if any of the patches in the Update object has been
|
2207
|
+
// pre-selected for download, otherwise we must figure out which one
|
2208
|
+
// to select ourselves.
|
2209
|
+
var selectedPatch = update.selectedPatch;
|
2210
|
+
|
2211
|
+
var state = readStatusFile(updateDir)
|
2212
|
+
|
2213
|
+
// If this is a patch that we know about, then select it. If it is a patch
|
2214
|
+
// that we do not know about, then remove it and use our default logic.
|
2215
|
+
var useComplete = false;
|
2216
|
+
if (selectedPatch) {
|
2217
|
+
LOG("Downloader", "found existing patch [state="+state+"]");
|
2218
|
+
switch (state) {
|
2219
|
+
case STATE_DOWNLOADING:
|
2220
|
+
LOG("Downloader", "resuming download");
|
2221
|
+
return selectedPatch;
|
2222
|
+
case STATE_PENDING:
|
2223
|
+
LOG("Downloader", "already downloaded and staged");
|
2224
|
+
return null;
|
2225
|
+
default:
|
2226
|
+
// Something went wrong when we tried to apply the previous patch.
|
2227
|
+
// Try the complete patch next time.
|
2228
|
+
if (update && selectedPatch.type == "partial") {
|
2229
|
+
useComplete = true;
|
2230
|
+
} else {
|
2231
|
+
// This is a pretty fatal error. Just bail.
|
2232
|
+
LOG("Downloader", "failed to apply complete patch!");
|
2233
|
+
writeStatusFile(updateDir, STATE_NONE);
|
2234
|
+
return null;
|
2235
|
+
}
|
2236
|
+
}
|
2237
|
+
|
2238
|
+
selectedPatch = null;
|
2239
|
+
}
|
2240
|
+
|
2241
|
+
// If we were not able to discover an update from a previous download, we
|
2242
|
+
// select the best patch from the given set.
|
2243
|
+
var partialPatch = getPatchOfType("partial");
|
2244
|
+
if (!useComplete)
|
2245
|
+
selectedPatch = partialPatch;
|
2246
|
+
if (!selectedPatch) {
|
2247
|
+
if (partialPatch)
|
2248
|
+
partialPatch.selected = false;
|
2249
|
+
selectedPatch = getPatchOfType("complete");
|
2250
|
+
}
|
2251
|
+
|
2252
|
+
// Restore the updateDir since we may have deleted it.
|
2253
|
+
updateDir = getUpdatesDir();
|
2254
|
+
|
2255
|
+
// if update only contains a partial patch, selectedPatch == null here if
|
2256
|
+
// the partial patch has been attempted and fails and we're trying to get a
|
2257
|
+
// complete patch
|
2258
|
+
if (selectedPatch)
|
2259
|
+
selectedPatch.selected = true;
|
2260
|
+
|
2261
|
+
update.isCompleteUpdate = useComplete;
|
2262
|
+
|
2263
|
+
// Reset the Active Update object on the Update Manager and flush the
|
2264
|
+
// Active Update DB.
|
2265
|
+
var um = Components.classes["@mozilla.org/updates/update-manager;1"]
|
2266
|
+
.getService(Components.interfaces.nsIUpdateManager);
|
2267
|
+
um.activeUpdate = update;
|
2268
|
+
|
2269
|
+
return selectedPatch;
|
2270
|
+
},
|
2271
|
+
|
2272
|
+
/**
|
2273
|
+
* Whether or not we are currently downloading something.
|
2274
|
+
*/
|
2275
|
+
get isBusy() {
|
2276
|
+
return this._request != null;
|
2277
|
+
},
|
2278
|
+
|
2279
|
+
/**
|
2280
|
+
* Download and stage the given update.
|
2281
|
+
* @param update
|
2282
|
+
* A nsIUpdate object to download a patch for. Cannot be null.
|
2283
|
+
*/
|
2284
|
+
downloadUpdate: function(update) {
|
2285
|
+
if (!update)
|
2286
|
+
throw Components.results.NS_ERROR_NULL_POINTER;
|
2287
|
+
|
2288
|
+
var updateDir = getUpdatesDir();
|
2289
|
+
|
2290
|
+
this._update = update;
|
2291
|
+
|
2292
|
+
// This function may return null, which indicates that there are no patches
|
2293
|
+
// to download.
|
2294
|
+
this._patch = this._selectPatch(update, updateDir);
|
2295
|
+
if (!this._patch) {
|
2296
|
+
LOG("Downloader", "no patch to download");
|
2297
|
+
return readStatusFile(updateDir);
|
2298
|
+
}
|
2299
|
+
this.isCompleteUpdate = this._patch.type == "complete";
|
2300
|
+
|
2301
|
+
var patchFile = updateDir.clone();
|
2302
|
+
patchFile.append(FILE_UPDATE_ARCHIVE);
|
2303
|
+
|
2304
|
+
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
2305
|
+
getService(Components.interfaces.nsIIOService);
|
2306
|
+
var uri = ios.newURI(this._patch.URL, null, null);
|
2307
|
+
|
2308
|
+
this._request =
|
2309
|
+
Components.classes["@mozilla.org/network/incremental-download;1"].
|
2310
|
+
createInstance(nsIIncrementalDownload);
|
2311
|
+
|
2312
|
+
LOG("Downloader", "downloadUpdate: Downloading from " + uri.spec + " to " +
|
2313
|
+
patchFile.path);
|
2314
|
+
|
2315
|
+
var interval = this.background ? DOWNLOAD_BACKGROUND_INTERVAL
|
2316
|
+
: DOWNLOAD_FOREGROUND_INTERVAL;
|
2317
|
+
this._request.init(uri, patchFile, DOWNLOAD_CHUNK_SIZE, interval);
|
2318
|
+
this._request.start(this, null);
|
2319
|
+
|
2320
|
+
writeStatusFile(updateDir, STATE_DOWNLOADING);
|
2321
|
+
this._patch.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
|
2322
|
+
this._patch.state = STATE_DOWNLOADING;
|
2323
|
+
var um = Components.classes["@mozilla.org/updates/update-manager;1"]
|
2324
|
+
.getService(Components.interfaces.nsIUpdateManager);
|
2325
|
+
um.saveUpdates();
|
2326
|
+
return STATE_DOWNLOADING;
|
2327
|
+
},
|
2328
|
+
|
2329
|
+
/**
|
2330
|
+
* An array of download listeners to notify when we receive
|
2331
|
+
* nsIRequestObserver or nsIProgressEventSink method calls.
|
2332
|
+
*/
|
2333
|
+
_listeners: [],
|
2334
|
+
|
2335
|
+
/**
|
2336
|
+
* Adds a listener to the download process
|
2337
|
+
* @param listener
|
2338
|
+
* A download listener, implementing nsIRequestObserver and
|
2339
|
+
* nsIProgressEventSink
|
2340
|
+
*/
|
2341
|
+
addDownloadListener: function(listener) {
|
2342
|
+
for (var i = 0; i < this._listeners.length; ++i) {
|
2343
|
+
if (this._listeners[i] == listener)
|
2344
|
+
return;
|
2345
|
+
}
|
2346
|
+
this._listeners.push(listener);
|
2347
|
+
},
|
2348
|
+
|
2349
|
+
/**
|
2350
|
+
* Removes a download listener
|
2351
|
+
* @param listener
|
2352
|
+
* The listener to remove.
|
2353
|
+
*/
|
2354
|
+
removeDownloadListener: function(listener) {
|
2355
|
+
for (var i = 0; i < this._listeners.length; ++i) {
|
2356
|
+
if (this._listeners[i] == listener) {
|
2357
|
+
this._listeners.splice(i, 1);
|
2358
|
+
return;
|
2359
|
+
}
|
2360
|
+
}
|
2361
|
+
},
|
2362
|
+
|
2363
|
+
/**
|
2364
|
+
* When the async request begins
|
2365
|
+
* @param request
|
2366
|
+
* The nsIRequest object for the transfer
|
2367
|
+
* @param context
|
2368
|
+
* Additional data
|
2369
|
+
*/
|
2370
|
+
onStartRequest: function(request, context) {
|
2371
|
+
request.QueryInterface(nsIIncrementalDownload);
|
2372
|
+
LOG("Downloader", "onStartRequest: " + request.URI.spec);
|
2373
|
+
|
2374
|
+
var listenerCount = this._listeners.length;
|
2375
|
+
for (var i = 0; i < listenerCount; ++i)
|
2376
|
+
this._listeners[i].onStartRequest(request, context);
|
2377
|
+
},
|
2378
|
+
|
2379
|
+
/**
|
2380
|
+
* When new data has been downloaded
|
2381
|
+
* @param request
|
2382
|
+
* The nsIRequest object for the transfer
|
2383
|
+
* @param context
|
2384
|
+
* Additional data
|
2385
|
+
* @param progress
|
2386
|
+
* The current number of bytes transferred
|
2387
|
+
* @param maxProgress
|
2388
|
+
* The total number of bytes that must be transferred
|
2389
|
+
*/
|
2390
|
+
onProgress: function(request, context, progress, maxProgress) {
|
2391
|
+
request.QueryInterface(nsIIncrementalDownload);
|
2392
|
+
LOG("Downloader.onProgress", "onProgress: " + request.URI.spec + ", " + progress + "/" + maxProgress);
|
2393
|
+
|
2394
|
+
var listenerCount = this._listeners.length;
|
2395
|
+
for (var i = 0; i < listenerCount; ++i) {
|
2396
|
+
var listener = this._listeners[i];
|
2397
|
+
if (listener instanceof Components.interfaces.nsIProgressEventSink)
|
2398
|
+
listener.onProgress(request, context, progress, maxProgress);
|
2399
|
+
}
|
2400
|
+
},
|
2401
|
+
|
2402
|
+
/**
|
2403
|
+
* When we have new status text
|
2404
|
+
* @param request
|
2405
|
+
* The nsIRequest object for the transfer
|
2406
|
+
* @param context
|
2407
|
+
* Additional data
|
2408
|
+
* @param status
|
2409
|
+
* A status code
|
2410
|
+
* @param statusText
|
2411
|
+
* Human readable version of |status|
|
2412
|
+
*/
|
2413
|
+
onStatus: function(request, context, status, statusText) {
|
2414
|
+
request.QueryInterface(nsIIncrementalDownload);
|
2415
|
+
LOG("Downloader", "onStatus: " + request.URI.spec + " status = " + status + ", text = " + statusText);
|
2416
|
+
var listenerCount = this._listeners.length;
|
2417
|
+
for (var i = 0; i < listenerCount; ++i) {
|
2418
|
+
var listener = this._listeners[i];
|
2419
|
+
if (listener instanceof Components.interfaces.nsIProgressEventSink)
|
2420
|
+
listener.onStatus(request, context, status, statusText);
|
2421
|
+
}
|
2422
|
+
},
|
2423
|
+
|
2424
|
+
/**
|
2425
|
+
* When data transfer ceases
|
2426
|
+
* @param request
|
2427
|
+
* The nsIRequest object for the transfer
|
2428
|
+
* @param context
|
2429
|
+
* Additional data
|
2430
|
+
* @param status
|
2431
|
+
* Status code containing the reason for the cessation.
|
2432
|
+
*/
|
2433
|
+
onStopRequest: function(request, context, status) {
|
2434
|
+
request.QueryInterface(nsIIncrementalDownload);
|
2435
|
+
LOG("Downloader", "onStopRequest: " + request.URI.spec + ", status = " + status);
|
2436
|
+
|
2437
|
+
var state = this._patch.state;
|
2438
|
+
var shouldShowPrompt = false;
|
2439
|
+
var deleteActiveUpdate = false;
|
2440
|
+
const NS_BINDING_ABORTED = 0x804b0002;
|
2441
|
+
const NS_ERROR_ABORT = 0x80004004;
|
2442
|
+
if (Components.isSuccessCode(status)) {
|
2443
|
+
var sbs =
|
2444
|
+
Components.classes["@mozilla.org/intl/stringbundle;1"].
|
2445
|
+
getService(Components.interfaces.nsIStringBundleService);
|
2446
|
+
var updateStrings = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
2447
|
+
if (this._verifyDownload()) {
|
2448
|
+
state = STATE_PENDING;
|
2449
|
+
|
2450
|
+
// We only need to explicitly show the prompt if this is a backround
|
2451
|
+
// download, since otherwise some kind of UI is already visible and
|
2452
|
+
// that UI will notify.
|
2453
|
+
if (this.background)
|
2454
|
+
shouldShowPrompt = true;
|
2455
|
+
|
2456
|
+
// Tell the updater.exe we're ready to apply.
|
2457
|
+
writeStatusFile(getUpdatesDir(), state);
|
2458
|
+
this._update.installDate = (new Date()).getTime();
|
2459
|
+
this._update.statusText = updateStrings.
|
2460
|
+
GetStringFromName("installPending");
|
2461
|
+
} else {
|
2462
|
+
LOG("Downloader", "onStopRequest: download verification failed");
|
2463
|
+
state = STATE_DOWNLOAD_FAILED;
|
2464
|
+
|
2465
|
+
var brandStrings = sbs.createBundle(URI_BRAND_PROPERTIES);
|
2466
|
+
var brandShortName = brandStrings.GetStringFromName("brandShortName");
|
2467
|
+
this._update.statusText = updateStrings.
|
2468
|
+
formatStringFromName("verificationError", [brandShortName], 1);
|
2469
|
+
|
2470
|
+
// TODO: use more informative error code here
|
2471
|
+
status = Components.results.NS_ERROR_UNEXPECTED;
|
2472
|
+
|
2473
|
+
var message = getStatusTextFromCode("verification_failed",
|
2474
|
+
"verification_failed");
|
2475
|
+
this._update.statusText = message;
|
2476
|
+
|
2477
|
+
if (this._update.isCompleteUpdate)
|
2478
|
+
deleteActiveUpdate = true;
|
2479
|
+
|
2480
|
+
// Destroy the updates directory, since we're done with it.
|
2481
|
+
cleanUpUpdatesDir();
|
2482
|
+
}
|
2483
|
+
}
|
2484
|
+
else if (status != NS_BINDING_ABORTED &&
|
2485
|
+
status != NS_ERROR_ABORT) {
|
2486
|
+
LOG("Downloader", "onStopRequest: Non-verification failure");
|
2487
|
+
// Some sort of other failure, log this in the |statusText| property
|
2488
|
+
state = STATE_DOWNLOAD_FAILED;
|
2489
|
+
|
2490
|
+
// XXXben - if |request| (The Incremental Download) provided a means
|
2491
|
+
// for accessing the http channel we could do more here.
|
2492
|
+
|
2493
|
+
const NS_BINDING_FAILED = 2152398849;
|
2494
|
+
this._update.statusText = getStatusTextFromCode(status,
|
2495
|
+
NS_BINDING_FAILED);
|
2496
|
+
|
2497
|
+
// Destroy the updates directory, since we're done with it.
|
2498
|
+
cleanUpUpdatesDir();
|
2499
|
+
|
2500
|
+
deleteActiveUpdate = true;
|
2501
|
+
}
|
2502
|
+
LOG("Downloader", "Setting state to: " + state);
|
2503
|
+
this._patch.state = state;
|
2504
|
+
var um =
|
2505
|
+
Components.classes["@mozilla.org/updates/update-manager;1"].
|
2506
|
+
getService(Components.interfaces.nsIUpdateManager);
|
2507
|
+
if (deleteActiveUpdate) {
|
2508
|
+
this._update.installDate = (new Date()).getTime();
|
2509
|
+
um.activeUpdate = null;
|
2510
|
+
}
|
2511
|
+
um.saveUpdates();
|
2512
|
+
|
2513
|
+
var listenerCount = this._listeners.length;
|
2514
|
+
for (var i = 0; i < listenerCount; ++i)
|
2515
|
+
this._listeners[i].onStopRequest(request, context, status);
|
2516
|
+
|
2517
|
+
this._request = null;
|
2518
|
+
|
2519
|
+
if (state == STATE_DOWNLOAD_FAILED) {
|
2520
|
+
if (!this._update.isCompleteUpdate) {
|
2521
|
+
var allFailed = true;
|
2522
|
+
|
2523
|
+
// If we were downloading a patch and the patch verification phase
|
2524
|
+
// failed, log this and then commence downloading the complete update.
|
2525
|
+
LOG("Downloader", "onStopRequest: Verification of patch failed, downloading complete update");
|
2526
|
+
this._update.isCompleteUpdate = true;
|
2527
|
+
var status = this.downloadUpdate(this._update);
|
2528
|
+
|
2529
|
+
if (status == STATE_NONE) {
|
2530
|
+
cleanupActiveUpdate();
|
2531
|
+
} else {
|
2532
|
+
allFailed = false;
|
2533
|
+
}
|
2534
|
+
// This will reset the |.state| property on this._update if a new
|
2535
|
+
// download initiates.
|
2536
|
+
}
|
2537
|
+
|
2538
|
+
// if we still fail after trying a complete download, give up completely
|
2539
|
+
if (allFailed) {
|
2540
|
+
// In all other failure cases, i.e. we're S.O.L. - no more failing over
|
2541
|
+
// ...
|
2542
|
+
|
2543
|
+
// If this was ever a foreground download, and now there is no UI active
|
2544
|
+
// (e.g. because the user closed the download window) and there was an
|
2545
|
+
// error, we must notify now. Otherwise we can keep the failure to
|
2546
|
+
// ourselves since the user won't be expecting it.
|
2547
|
+
try {
|
2548
|
+
this._update.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
|
2549
|
+
var fgdl = this._update.getProperty("foregroundDownload");
|
2550
|
+
}
|
2551
|
+
catch (e) {
|
2552
|
+
}
|
2553
|
+
|
2554
|
+
if (fgdl == "true") {
|
2555
|
+
var prompter =
|
2556
|
+
Components.classes["@mozilla.org/updates/update-prompt;1"].
|
2557
|
+
createInstance(Components.interfaces.nsIUpdatePrompt);
|
2558
|
+
this._update.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
|
2559
|
+
this._update.setProperty("downloadFailed", "true");
|
2560
|
+
prompter.showUpdateError(this._update);
|
2561
|
+
}
|
2562
|
+
}
|
2563
|
+
|
2564
|
+
// the complete download succeeded or total failure was handled, so exit
|
2565
|
+
return;
|
2566
|
+
}
|
2567
|
+
|
2568
|
+
// Do this after *everything* else, since it will likely cause the app
|
2569
|
+
// to shut down.
|
2570
|
+
if (shouldShowPrompt) {
|
2571
|
+
// Notify the user that an update has been downloaded and is ready for
|
2572
|
+
// installation (i.e. that they should restart the application). We do
|
2573
|
+
// not notify on failed update attempts.
|
2574
|
+
var prompter =
|
2575
|
+
Components.classes["@mozilla.org/updates/update-prompt;1"].
|
2576
|
+
createInstance(Components.interfaces.nsIUpdatePrompt);
|
2577
|
+
prompter.showUpdateDownloaded(this._update);
|
2578
|
+
}
|
2579
|
+
},
|
2580
|
+
|
2581
|
+
/**
|
2582
|
+
* See nsIInterfaceRequestor.idl
|
2583
|
+
*/
|
2584
|
+
getInterface: function(iid) {
|
2585
|
+
// The network request may require proxy authentication, so provide the
|
2586
|
+
// default nsIAuthPrompt if requested.
|
2587
|
+
if (iid.equals(Components.interfaces.nsIAuthPrompt)) {
|
2588
|
+
var prompt =
|
2589
|
+
Components.classes["@mozilla.org/network/default-auth-prompt;1"].
|
2590
|
+
createInstance();
|
2591
|
+
return prompt.QueryInterface(iid);
|
2592
|
+
}
|
2593
|
+
Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
|
2594
|
+
return null;
|
2595
|
+
},
|
2596
|
+
|
2597
|
+
/**
|
2598
|
+
* See nsISupports.idl
|
2599
|
+
*/
|
2600
|
+
QueryInterface: function(iid) {
|
2601
|
+
if (!iid.equals(Components.interfaces.nsIRequestObserver) &&
|
2602
|
+
!iid.equals(Components.interfaces.nsIProgressEventSink) &&
|
2603
|
+
!iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
|
2604
|
+
!iid.equals(Components.interfaces.nsISupports))
|
2605
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
2606
|
+
return this;
|
2607
|
+
}
|
2608
|
+
};
|
2609
|
+
|
2610
|
+
/**
|
2611
|
+
* A manager for update check timers. Manages timers that fire over long
|
2612
|
+
* periods of time (e.g. days, weeks).
|
2613
|
+
* @constructor
|
2614
|
+
*/
|
2615
|
+
function TimerManager() {
|
2616
|
+
getObserverService().addObserver(this, "xpcom-shutdown", false);
|
2617
|
+
|
2618
|
+
const nsITimer = Components.interfaces.nsITimer;
|
2619
|
+
this._timer = Components.classes["@mozilla.org/timer;1"]
|
2620
|
+
.createInstance(nsITimer);
|
2621
|
+
var timerInterval = getPref("getIntPref", PREF_APP_UPDATE_TIMER, 600000);
|
2622
|
+
this._timer.initWithCallback(this, timerInterval,
|
2623
|
+
nsITimer.TYPE_REPEATING_SLACK);
|
2624
|
+
}
|
2625
|
+
TimerManager.prototype = {
|
2626
|
+
/**
|
2627
|
+
* See nsIObserver.idl
|
2628
|
+
*/
|
2629
|
+
observe: function(subject, topic, data) {
|
2630
|
+
if (topic == "xpcom-shutdown") {
|
2631
|
+
getObserverService().removeObserver(this, "xpcom-shutdown");
|
2632
|
+
|
2633
|
+
// Release everything we hold onto.
|
2634
|
+
for (var timerID in this._timers)
|
2635
|
+
delete this._timers[timerID];
|
2636
|
+
this._timer = null;
|
2637
|
+
this._timers = null;
|
2638
|
+
}
|
2639
|
+
},
|
2640
|
+
|
2641
|
+
/**
|
2642
|
+
* The Checker Timer
|
2643
|
+
*/
|
2644
|
+
_timer: null,
|
2645
|
+
|
2646
|
+
/**
|
2647
|
+
* The set of registered timers.
|
2648
|
+
*/
|
2649
|
+
_timers: { },
|
2650
|
+
|
2651
|
+
/**
|
2652
|
+
* Called when the checking timer fires.
|
2653
|
+
* @param timer
|
2654
|
+
* The checking timer that fired.
|
2655
|
+
*/
|
2656
|
+
notify: function(timer) {
|
2657
|
+
for (var timerID in this._timers) {
|
2658
|
+
var timerData = this._timers[timerID];
|
2659
|
+
var lastUpdateTime = timerData.lastUpdateTime;
|
2660
|
+
var now = Math.round(Date.now() / 1000);
|
2661
|
+
|
2662
|
+
// Fudge the lastUpdateTime by some random increment of the update
|
2663
|
+
// check interval (e.g. some random slice of 10 minutes) so that when
|
2664
|
+
// the time comes to check, we offset each client request by a random
|
2665
|
+
// amount so they don't all hit at once. app.update.timer is in milliseconds,
|
2666
|
+
// whereas app.update.lastUpdateTime is in seconds
|
2667
|
+
var timerInterval = getPref("getIntPref", PREF_APP_UPDATE_TIMER, 600000);
|
2668
|
+
lastUpdateTime += Math.round(Math.random() * timerInterval / 1000);
|
2669
|
+
|
2670
|
+
if ((now - lastUpdateTime) > timerData.interval &&
|
2671
|
+
timerData.callback instanceof Components.interfaces.nsITimerCallback) {
|
2672
|
+
timerData.callback.notify(timer);
|
2673
|
+
timerData.lastUpdateTime = now;
|
2674
|
+
var preference = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, timerID);
|
2675
|
+
gPref.setIntPref(preference, now);
|
2676
|
+
}
|
2677
|
+
}
|
2678
|
+
},
|
2679
|
+
|
2680
|
+
/**
|
2681
|
+
* See nsIUpdateService.idl
|
2682
|
+
*/
|
2683
|
+
registerTimer: function(id, callback, interval) {
|
2684
|
+
var preference = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, id);
|
2685
|
+
var now = Math.round(Date.now() / 1000);
|
2686
|
+
var lastUpdateTime = null;
|
2687
|
+
if (gPref.prefHasUserValue(preference)) {
|
2688
|
+
lastUpdateTime = gPref.getIntPref(preference);
|
2689
|
+
} else {
|
2690
|
+
gPref.setIntPref(preference, now);
|
2691
|
+
lastUpdateTime = now;
|
2692
|
+
}
|
2693
|
+
this._timers[id] = { callback : callback,
|
2694
|
+
interval : interval,
|
2695
|
+
lastUpdateTime : lastUpdateTime };
|
2696
|
+
},
|
2697
|
+
|
2698
|
+
/**
|
2699
|
+
* See nsISupports.idl
|
2700
|
+
*/
|
2701
|
+
QueryInterface: function(iid) {
|
2702
|
+
if (!iid.equals(Components.interfaces.nsIUpdateTimerManager) &&
|
2703
|
+
!iid.equals(Components.interfaces.nsITimerCallback) &&
|
2704
|
+
!iid.equals(Components.interfaces.nsIObserver) &&
|
2705
|
+
!iid.equals(Components.interfaces.nsISupports))
|
2706
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
2707
|
+
return this;
|
2708
|
+
}
|
2709
|
+
};
|
2710
|
+
|
2711
|
+
//@line 2684 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2712
|
+
/**
|
2713
|
+
* UpdatePrompt
|
2714
|
+
* An object which can prompt the user with information about updates, request
|
2715
|
+
* action, etc. Embedding clients can override this component with one that
|
2716
|
+
* invokes a native front end.
|
2717
|
+
* @constructor
|
2718
|
+
*/
|
2719
|
+
function UpdatePrompt() {
|
2720
|
+
}
|
2721
|
+
UpdatePrompt.prototype = {
|
2722
|
+
/**
|
2723
|
+
* See nsIUpdateService.idl
|
2724
|
+
*/
|
2725
|
+
checkForUpdates: function() {
|
2726
|
+
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard",
|
2727
|
+
null, null);
|
2728
|
+
},
|
2729
|
+
|
2730
|
+
/**
|
2731
|
+
* See nsIUpdateService.idl
|
2732
|
+
*/
|
2733
|
+
showUpdateAvailable: function(update) {
|
2734
|
+
if (this._enabled) {
|
2735
|
+
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard",
|
2736
|
+
"updatesavailable", update);
|
2737
|
+
}
|
2738
|
+
},
|
2739
|
+
|
2740
|
+
/**
|
2741
|
+
* See nsIUpdateService.idl
|
2742
|
+
*/
|
2743
|
+
showUpdateDownloaded: function(update) {
|
2744
|
+
if (this._enabled) {
|
2745
|
+
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard",
|
2746
|
+
"finishedBackground", update);
|
2747
|
+
}
|
2748
|
+
},
|
2749
|
+
|
2750
|
+
/**
|
2751
|
+
* See nsIUpdateService.idl
|
2752
|
+
*/
|
2753
|
+
showUpdateInstalled: function(update) {
|
2754
|
+
var showUpdateInstalledUI = getPref("getBoolPref",
|
2755
|
+
PREF_APP_UPDATE_SHOW_INSTALLED_UI, true);
|
2756
|
+
if (this._enabled && showUpdateInstalledUI) {
|
2757
|
+
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard",
|
2758
|
+
"installed", update);
|
2759
|
+
}
|
2760
|
+
},
|
2761
|
+
|
2762
|
+
/**
|
2763
|
+
* See nsIUpdateService.idl
|
2764
|
+
*/
|
2765
|
+
showUpdateError: function(update) {
|
2766
|
+
if (this._enabled) {
|
2767
|
+
// In some cases, we want to just show a simple alert dialog:
|
2768
|
+
if (update.state == STATE_FAILED && update.errorCode == WRITE_ERROR) {
|
2769
|
+
var sbs =
|
2770
|
+
Components.classes["@mozilla.org/intl/stringbundle;1"].
|
2771
|
+
getService(Components.interfaces.nsIStringBundleService);
|
2772
|
+
var updateBundle = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
2773
|
+
var title = updateBundle.GetStringFromName("updaterIOErrorTitle");
|
2774
|
+
var text = updateBundle.formatStringFromName("updaterIOErrorText",
|
2775
|
+
[gApp.name], 1);
|
2776
|
+
var ww =
|
2777
|
+
Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
|
2778
|
+
getService(Components.interfaces.nsIWindowWatcher);
|
2779
|
+
ww.getNewPrompter(null).alert(title, text);
|
2780
|
+
} else {
|
2781
|
+
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard",
|
2782
|
+
"errors", update);
|
2783
|
+
}
|
2784
|
+
}
|
2785
|
+
},
|
2786
|
+
|
2787
|
+
/**
|
2788
|
+
* See nsIUpdateService.idl
|
2789
|
+
*/
|
2790
|
+
showUpdateHistory: function(parent) {
|
2791
|
+
this._showUI(parent, URI_UPDATE_HISTORY_DIALOG, "modal,dialog=yes", "Update:History",
|
2792
|
+
null, null);
|
2793
|
+
},
|
2794
|
+
|
2795
|
+
/**
|
2796
|
+
* Whether or not we are enabled (i.e. not in Silent mode)
|
2797
|
+
*/
|
2798
|
+
get _enabled() {
|
2799
|
+
return !getPref("getBoolPref", PREF_APP_UPDATE_SILENT, false);
|
2800
|
+
},
|
2801
|
+
|
2802
|
+
/**
|
2803
|
+
* Show the Update Checking UI
|
2804
|
+
* @param parent
|
2805
|
+
* A parent window, can be null
|
2806
|
+
* @param uri
|
2807
|
+
* The URI string of the dialog to show
|
2808
|
+
* @param name
|
2809
|
+
* The Window Name of the dialog to show, in case it is already open
|
2810
|
+
* and can merely be focused
|
2811
|
+
* @param page
|
2812
|
+
* The page of the wizard to be displayed, if one is already open.
|
2813
|
+
* @param update
|
2814
|
+
* An update to pass to the UI in the window arguments.
|
2815
|
+
* Can be null
|
2816
|
+
*/
|
2817
|
+
_showUI: function(parent, uri, features, name, page, update) {
|
2818
|
+
var ary = null;
|
2819
|
+
if (update) {
|
2820
|
+
ary = Components.classes["@mozilla.org/supports-array;1"]
|
2821
|
+
.createInstance(Components.interfaces.nsISupportsArray);
|
2822
|
+
ary.AppendElement(update);
|
2823
|
+
}
|
2824
|
+
|
2825
|
+
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
2826
|
+
.getService(Components.interfaces.nsIWindowMediator);
|
2827
|
+
var win = wm.getMostRecentWindow(name);
|
2828
|
+
if (win) {
|
2829
|
+
if (page && "setCurrentPage" in win)
|
2830
|
+
win.setCurrentPage(page);
|
2831
|
+
win.focus();
|
2832
|
+
}
|
2833
|
+
else {
|
2834
|
+
var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no";
|
2835
|
+
if (features)
|
2836
|
+
openFeatures += "," + features;
|
2837
|
+
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
2838
|
+
.getService(Components.interfaces.nsIWindowWatcher);
|
2839
|
+
ww.openWindow(parent, uri, "", openFeatures, ary);
|
2840
|
+
}
|
2841
|
+
},
|
2842
|
+
|
2843
|
+
/**
|
2844
|
+
* See nsISupports.idl
|
2845
|
+
*/
|
2846
|
+
QueryInterface: function(iid) {
|
2847
|
+
if (!iid.equals(Components.interfaces.nsIUpdatePrompt) &&
|
2848
|
+
!iid.equals(Components.interfaces.nsISupports))
|
2849
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
2850
|
+
return this;
|
2851
|
+
}
|
2852
|
+
};
|
2853
|
+
//@line 2826 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2854
|
+
|
2855
|
+
var gModule = {
|
2856
|
+
registerSelf: function(componentManager, fileSpec, location, type) {
|
2857
|
+
componentManager = componentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
2858
|
+
|
2859
|
+
for (var key in this._objects) {
|
2860
|
+
var obj = this._objects[key];
|
2861
|
+
componentManager.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
|
2862
|
+
fileSpec, location, type);
|
2863
|
+
}
|
2864
|
+
|
2865
|
+
// Make the Update Service a startup observer
|
2866
|
+
var categoryManager = Components.classes["@mozilla.org/categorymanager;1"]
|
2867
|
+
.getService(Components.interfaces.nsICategoryManager);
|
2868
|
+
categoryManager.addCategoryEntry("app-startup", this._objects.service.className,
|
2869
|
+
"service," + this._objects.service.contractID,
|
2870
|
+
true, true, null);
|
2871
|
+
},
|
2872
|
+
|
2873
|
+
getClassObject: function(componentManager, cid, iid) {
|
2874
|
+
if (!iid.equals(Components.interfaces.nsIFactory))
|
2875
|
+
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
2876
|
+
|
2877
|
+
for (var key in this._objects) {
|
2878
|
+
if (cid.equals(this._objects[key].CID))
|
2879
|
+
return this._objects[key].factory;
|
2880
|
+
}
|
2881
|
+
|
2882
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
2883
|
+
},
|
2884
|
+
|
2885
|
+
_objects: {
|
2886
|
+
service: { CID : Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"),
|
2887
|
+
contractID : "@mozilla.org/updates/update-service;1",
|
2888
|
+
className : "Update Service",
|
2889
|
+
factory : makeFactory(UpdateService)
|
2890
|
+
},
|
2891
|
+
checker: { CID : Components.ID("{898CDC9B-E43F-422F-9CC4-2F6291B415A3}"),
|
2892
|
+
contractID : "@mozilla.org/updates/update-checker;1",
|
2893
|
+
className : "Update Checker",
|
2894
|
+
factory : makeFactory(Checker)
|
2895
|
+
},
|
2896
|
+
//@line 2869 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2897
|
+
prompt: { CID : Components.ID("{27ABA825-35B5-4018-9FDD-F99250A0E722}"),
|
2898
|
+
contractID : "@mozilla.org/updates/update-prompt;1",
|
2899
|
+
className : "Update Prompt",
|
2900
|
+
factory : makeFactory(UpdatePrompt)
|
2901
|
+
},
|
2902
|
+
//@line 2875 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2903
|
+
timers: { CID : Components.ID("{B322A5C0-A419-484E-96BA-D7182163899F}"),
|
2904
|
+
contractID : "@mozilla.org/updates/timer-manager;1",
|
2905
|
+
className : "Timer Manager",
|
2906
|
+
factory : makeFactory(TimerManager)
|
2907
|
+
},
|
2908
|
+
manager: { CID : Components.ID("{093C2356-4843-4C65-8709-D7DBCBBE7DFB}"),
|
2909
|
+
contractID : "@mozilla.org/updates/update-manager;1",
|
2910
|
+
className : "Update Manager",
|
2911
|
+
factory : makeFactory(UpdateManager)
|
2912
|
+
},
|
2913
|
+
},
|
2914
|
+
|
2915
|
+
canUnload: function(componentManager) {
|
2916
|
+
return true;
|
2917
|
+
}
|
2918
|
+
};
|
2919
|
+
|
2920
|
+
/**
|
2921
|
+
* Creates a factory for instances of an object created using the passed-in
|
2922
|
+
* constructor.
|
2923
|
+
*/
|
2924
|
+
function makeFactory(ctor) {
|
2925
|
+
function ci(outer, iid) {
|
2926
|
+
if (outer != null)
|
2927
|
+
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
2928
|
+
return (new ctor()).QueryInterface(iid);
|
2929
|
+
}
|
2930
|
+
return { createInstance: ci };
|
2931
|
+
}
|
2932
|
+
|
2933
|
+
function NSGetModule(compMgr, fileSpec) {
|
2934
|
+
return gModule;
|
2935
|
+
}
|
2936
|
+
|
2937
|
+
/**
|
2938
|
+
* Determines whether or there are installed addons which are incompatible
|
2939
|
+
* with this update.
|
2940
|
+
* @param update
|
2941
|
+
* The update to check compatibility against
|
2942
|
+
* @returns true if there are no addons installed that are incompatible with
|
2943
|
+
* the specified update, false otherwise.
|
2944
|
+
*/
|
2945
|
+
function isCompatible(update) {
|
2946
|
+
//@line 2919 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2947
|
+
var em =
|
2948
|
+
Components.classes["@mozilla.org/extensions/manager;1"].
|
2949
|
+
getService(Components.interfaces.nsIExtensionManager);
|
2950
|
+
var items = em.getIncompatibleItemList("", update.extensionVersion,
|
2951
|
+
nsIUpdateItem.TYPE_ADDON, false, { });
|
2952
|
+
return items.length == 0;
|
2953
|
+
//@line 2928 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2954
|
+
}
|
2955
|
+
|
2956
|
+
/**
|
2957
|
+
* Shows a prompt for an update, provided there are no incompatible addons.
|
2958
|
+
* If there are, kick off an update check and see if updates are available
|
2959
|
+
* that will resolve the incompatibilities.
|
2960
|
+
* @param update
|
2961
|
+
* The available update to show
|
2962
|
+
*/
|
2963
|
+
function showPromptIfNoIncompatibilities(update) {
|
2964
|
+
function showPrompt(update) {
|
2965
|
+
LOG("UpdateService", "_selectAndInstallUpdate: need to prompt user before continuing...");
|
2966
|
+
var prompter =
|
2967
|
+
Components.classes["@mozilla.org/updates/update-prompt;1"].
|
2968
|
+
createInstance(Components.interfaces.nsIUpdatePrompt);
|
2969
|
+
prompter.showUpdateAvailable(update);
|
2970
|
+
}
|
2971
|
+
|
2972
|
+
//@line 2947 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
2973
|
+
/**
|
2974
|
+
* Determines if an addon is compatible with a particular update.
|
2975
|
+
* @param addon
|
2976
|
+
* The addon to check
|
2977
|
+
* @param version
|
2978
|
+
* The extensionVersion of the update to check for compatibility
|
2979
|
+
* against.
|
2980
|
+
* @returns true if the addon is compatible, false otherwise
|
2981
|
+
*/
|
2982
|
+
function addonIsCompatible(addon, version) {
|
2983
|
+
var vc =
|
2984
|
+
Components.classes["@mozilla.org/xpcom/version-comparator;1"].
|
2985
|
+
getService(Components.interfaces.nsIVersionComparator);
|
2986
|
+
return (vc.compare(version, addon.minAppVersion) >= 0) &&
|
2987
|
+
(vc.compare(version, addon.maxAppVersion) <= 0);
|
2988
|
+
}
|
2989
|
+
|
2990
|
+
/**
|
2991
|
+
* An object implementing nsIAddonUpdateCheckListener that looks for
|
2992
|
+
* available updates to addons and if updates are found that will make the
|
2993
|
+
* user's installed addon set compatible with the update, suppresses the
|
2994
|
+
* prompt that would otherwise be shown.
|
2995
|
+
* @param addons
|
2996
|
+
* An array of incompatible addons that are installed.
|
2997
|
+
* @constructor
|
2998
|
+
*/
|
2999
|
+
function Listener(addons) {
|
3000
|
+
this._addons = addons;
|
3001
|
+
}
|
3002
|
+
Listener.prototype = {
|
3003
|
+
_addons: null,
|
3004
|
+
|
3005
|
+
/**
|
3006
|
+
* See nsIUpdateService.idl
|
3007
|
+
*/
|
3008
|
+
onUpdateStarted: function() {
|
3009
|
+
},
|
3010
|
+
onUpdateEnded: function() {
|
3011
|
+
// There are still incompatibilities, even after an extension update
|
3012
|
+
// check to see if there were newer, compatible versions available, so
|
3013
|
+
// we have to prompt.
|
3014
|
+
//
|
3015
|
+
// PREF_APP_UPDATE_INCOMPATIBLE_MODE controls the mode in which we
|
3016
|
+
// handle incompatibilities:
|
3017
|
+
// 0 We count both VersionInfo updates _and_ NewerVersion updates
|
3018
|
+
// against the list of incompatible addons installed - i.e. if
|
3019
|
+
// Foo 1.2 is installed and it is incompatible with the update, and
|
3020
|
+
// we find Foo 2.0 which is but which is not yet downloaded or
|
3021
|
+
// installed, then we do NOT prompt because the user can download
|
3022
|
+
// Foo 2.0 when they restart after the update during the mismatch
|
3023
|
+
// checking UI. This is the default, since it suppresses most
|
3024
|
+
// prompt dialogs.
|
3025
|
+
// 1 We count only VersionInfo updates against the list of
|
3026
|
+
// incompatible addons installed - i.e. if the situation above
|
3027
|
+
// with Foo 1.2 and available update to 2.0 applies, we DO show
|
3028
|
+
// the prompt since a download operation will be required after
|
3029
|
+
// the update. This is not the default and is supplied only as
|
3030
|
+
// a hidden option for those that want it.
|
3031
|
+
var mode = getPref("getIntPref", PREF_APP_UPDATE_INCOMPATIBLE_MODE,
|
3032
|
+
INCOMPATIBLE_MODE_NEWVERSIONS);
|
3033
|
+
if ((mode == 0 && this._addons.length) || !isCompatible(update))
|
3034
|
+
showPrompt(update);
|
3035
|
+
},
|
3036
|
+
onAddonUpdateStarted: function(addon) {
|
3037
|
+
},
|
3038
|
+
onAddonUpdateEnded: function(addon, status) {
|
3039
|
+
if (status == Components.interfaces.nsIAddonUpdateCheckListener.STATUS_UPDATE &&
|
3040
|
+
addonIsCompatible(addon, update.extensionVersion)) {
|
3041
|
+
for (var i = 0; i < this._addons.length; ++i) {
|
3042
|
+
if (this._addons[i] == addon) {
|
3043
|
+
this._addons.splice(i, 1);
|
3044
|
+
break;
|
3045
|
+
}
|
3046
|
+
}
|
3047
|
+
}
|
3048
|
+
},
|
3049
|
+
/**
|
3050
|
+
* See nsISupports.idl
|
3051
|
+
*/
|
3052
|
+
QueryInterface: function(iid) {
|
3053
|
+
if (!iid.equals(Components.interfaces.nsIAddonUpdateCheckListener) &&
|
3054
|
+
!iid.equals(Components.interfaces.nsISupports))
|
3055
|
+
throw Components.results.NS_ERROR_NO_INTERFACE;
|
3056
|
+
return this;
|
3057
|
+
}
|
3058
|
+
};
|
3059
|
+
|
3060
|
+
if (!isCompatible(update)) {
|
3061
|
+
var em =
|
3062
|
+
Components.classes["@mozilla.org/extensions/manager;1"].
|
3063
|
+
getService(Components.interfaces.nsIExtensionManager);
|
3064
|
+
var listener = new Listener(em.getIncompatibleItemList("",
|
3065
|
+
update.extensionVersion, nsIUpdateItem.TYPE_ADDON, false, { }));
|
3066
|
+
// See documentation on |mode| above.
|
3067
|
+
var mode = getPref("getIntPref", PREF_APP_UPDATE_INCOMPATIBLE_MODE,
|
3068
|
+
INCOMPATIBLE_MODE_NEWVERSIONS);
|
3069
|
+
em.update([], 0, mode != 0, listener);
|
3070
|
+
}
|
3071
|
+
else
|
3072
|
+
//@line 3047 "/c/mozilla/toolkit/mozapps/update/src/nsUpdateService.js.in"
|
3073
|
+
showPrompt(update);
|
3074
|
+
}
|