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.
Files changed (430) hide show
  1. data/README +79 -0
  2. data/Rakefile +288 -0
  3. data/doc_src/ogre.rb +246 -0
  4. data/doc_src/ois.rb +67 -0
  5. data/lib/application.rb +146 -0
  6. data/lib/application_frame_listener.rb +302 -0
  7. data/lib/application_loading_bar.rb +115 -0
  8. data/lib/constants.rb +51 -0
  9. data/lib/method_fixes.rb +42 -0
  10. data/lib/ogre.so +0 -0
  11. data/lib/ruby_ois.so +0 -0
  12. data/ogre.rb +25 -0
  13. data/platform.rb +23 -0
  14. data/samples/Ogre.log +261 -0
  15. data/samples/bsp.rb +76 -0
  16. data/samples/cg.dll +0 -0
  17. data/samples/grass.rb +325 -0
  18. data/samples/js3250.dll +0 -0
  19. data/samples/lighting.rb +138 -0
  20. data/samples/media/materials/programs/Grass.cg +30 -0
  21. data/samples/media/materials/programs/OffsetMapping.cg +97 -0
  22. data/samples/media/materials/programs/OffsetMapping.hlsl +135 -0
  23. data/samples/media/materials/programs/OffsetMappingFp.glsl +69 -0
  24. data/samples/media/materials/programs/OffsetMappingVp.glsl +54 -0
  25. data/samples/media/materials/programs/OffsetMapping_specular.asm +44 -0
  26. data/samples/media/materials/scripts/CloudySky.material +17 -0
  27. data/samples/media/materials/scripts/CubeMapping.material +34 -0
  28. data/samples/media/materials/scripts/Flare.material +17 -0
  29. data/samples/media/materials/scripts/Grass.material +63 -0
  30. data/samples/media/materials/scripts/Knot.material +14 -0
  31. data/samples/media/materials/scripts/MorningSkyBox.material +17 -0
  32. data/samples/media/materials/scripts/Offset.material +124 -0
  33. data/samples/media/materials/scripts/Ogre.material +119 -0
  34. data/samples/media/materials/scripts/RZR-002.material +15 -0
  35. data/samples/media/materials/scripts/Razor.material +14 -0
  36. data/samples/media/materials/scripts/Ribbon.material +19 -0
  37. data/samples/media/materials/scripts/RustySteel.material +14 -0
  38. data/samples/media/materials/scripts/SpaceSkyBox.material +17 -0
  39. data/samples/media/materials/scripts/SpaceSkyPlane.material +17 -0
  40. data/samples/media/materials/scripts/TextureEffects.material +15 -0
  41. data/samples/media/materials/scripts/dragon.material +42 -0
  42. data/samples/media/materials/scripts/smoke.material +18 -0
  43. data/samples/media/materials/textures/GreenSkin.jpg +0 -0
  44. data/samples/media/materials/textures/MtlPlat2.jpg +0 -0
  45. data/samples/media/materials/textures/RZR-002.png +0 -0
  46. data/samples/media/materials/textures/RustedMetal.jpg +0 -0
  47. data/samples/media/materials/textures/RustySteel.jpg +0 -0
  48. data/samples/media/materials/textures/Water02.jpg +0 -0
  49. data/samples/media/materials/textures/WeirdEye.png +0 -0
  50. data/samples/media/materials/textures/clouds.jpg +0 -0
  51. data/samples/media/materials/textures/cursor.png +0 -0
  52. data/samples/media/materials/textures/dirt01.jpg +0 -0
  53. data/samples/media/materials/textures/flare.png +0 -0
  54. data/samples/media/materials/textures/gras_02.png +0 -0
  55. data/samples/media/materials/textures/grass_1024.jpg +0 -0
  56. data/samples/media/materials/textures/ogreborder.png +0 -0
  57. data/samples/media/materials/textures/ogreborderUp.png +0 -0
  58. data/samples/media/materials/textures/ribbonband.png +0 -0
  59. data/samples/media/materials/textures/rockwall.tga +0 -0
  60. data/samples/media/materials/textures/rockwall_NH.tga +0 -0
  61. data/samples/media/materials/textures/smoke.png +0 -0
  62. data/samples/media/materials/textures/smokecolors.png +0 -0
  63. data/samples/media/materials/textures/spacesky.jpg +0 -0
  64. data/samples/media/materials/textures/spheremap.png +0 -0
  65. data/samples/media/materials/textures/texmap2.jpg +0 -0
  66. data/samples/media/models/RZR-002.mesh +0 -0
  67. data/samples/media/models/geosphere4500.mesh +0 -0
  68. data/samples/media/models/geosphere8000.mesh +0 -0
  69. data/samples/media/models/knot.mesh +0 -0
  70. data/samples/media/models/ogrehead.mesh +0 -0
  71. data/samples/media/models/razor.mesh +0 -0
  72. data/samples/media/models/sphere.mesh +0 -0
  73. data/samples/media/overlays/CubeMapping.overlay +139 -0
  74. data/samples/media/packs/OgreCore.zip +0 -0
  75. data/samples/media/packs/chiropteraDM.pk3 +0 -0
  76. data/samples/media/packs/chiropteraDM.txt +99 -0
  77. data/samples/media/packs/cubemap.zip +0 -0
  78. data/samples/media/packs/cubemapsJS.zip +0 -0
  79. data/samples/media/packs/dragon.zip +0 -0
  80. data/samples/media/packs/skybox.zip +0 -0
  81. data/samples/media/particles/smoke.particle +43 -0
  82. data/samples/media.cfg +22 -0
  83. data/samples/navi/Media/NaviDemo.material +60 -0
  84. data/samples/navi/Media/OgreCore.zip +0 -0
  85. data/samples/navi/Media/cerulean.jpg +0 -0
  86. data/samples/navi/Media/clouds.jpg +0 -0
  87. data/samples/navi/Media/controlsNaviMask.png +0 -0
  88. data/samples/navi/Media/grass.jpg +0 -0
  89. data/samples/navi/Media/knot.mesh +0 -0
  90. data/samples/navi/Media/testNaviMask.png +0 -0
  91. data/samples/navi/NaviLocal/Navi.js +136 -0
  92. data/samples/navi/NaviLocal/buttonBg.jpg +0 -0
  93. data/samples/navi/NaviLocal/controls.html +303 -0
  94. data/samples/navi/NaviLocal/knobBg.jpg +0 -0
  95. data/samples/navi/NaviLocal/moo.dropdownmenu.js +87 -0
  96. data/samples/navi/NaviLocal/mootools.v1.1.js +6964 -0
  97. data/samples/navi/NaviLocal/naviLogo.html +32 -0
  98. data/samples/navi/NaviLocal/naviLogo.png +0 -0
  99. data/samples/navi/NaviLocal/pageBg.jpg +0 -0
  100. data/samples/navi/NaviLocal/sliderBg.jpg +0 -0
  101. data/samples/navi/NaviLocal/test.html +5 -0
  102. data/samples/navi/NaviLocal/welcome.html +36 -0
  103. data/samples/navi/NaviLocal/welcome.png +0 -0
  104. data/samples/navi/chrome/chromelist.txt +597 -0
  105. data/samples/navi/chrome/classic.jar +0 -0
  106. data/samples/navi/chrome/classic.manifest +4 -0
  107. data/samples/navi/chrome/comm.jar +0 -0
  108. data/samples/navi/chrome/comm.manifest +2 -0
  109. data/samples/navi/chrome/en-US.jar +0 -0
  110. data/samples/navi/chrome/en-US.manifest +9 -0
  111. data/samples/navi/chrome/toolkit.jar +0 -0
  112. data/samples/navi/chrome/toolkit.manifest +6 -0
  113. data/samples/navi/components/FeedProcessor.js +1825 -0
  114. data/samples/navi/components/alerts.xpt +0 -0
  115. data/samples/navi/components/appshell.xpt +0 -0
  116. data/samples/navi/components/appstartup.xpt +0 -0
  117. data/samples/navi/components/auth.dll +0 -0
  118. data/samples/navi/components/autocomplete.xpt +0 -0
  119. data/samples/navi/components/autoconfig.dll +0 -0
  120. data/samples/navi/components/autoconfig.xpt +0 -0
  121. data/samples/navi/components/caps.xpt +0 -0
  122. data/samples/navi/components/chardet.xpt +0 -0
  123. data/samples/navi/components/chrome.xpt +0 -0
  124. data/samples/navi/components/commandhandler.xpt +0 -0
  125. data/samples/navi/components/commandlines.xpt +0 -0
  126. data/samples/navi/components/composer.xpt +0 -0
  127. data/samples/navi/components/compreg.dat +1474 -0
  128. data/samples/navi/components/content_base.xpt +0 -0
  129. data/samples/navi/components/content_html.xpt +0 -0
  130. data/samples/navi/components/content_htmldoc.xpt +0 -0
  131. data/samples/navi/components/content_xmldoc.xpt +0 -0
  132. data/samples/navi/components/content_xslt.xpt +0 -0
  133. data/samples/navi/components/content_xtf.xpt +0 -0
  134. data/samples/navi/components/directory.xpt +0 -0
  135. data/samples/navi/components/docshell_base.xpt +0 -0
  136. data/samples/navi/components/dom.xpt +0 -0
  137. data/samples/navi/components/dom_base.xpt +0 -0
  138. data/samples/navi/components/dom_canvas.xpt +0 -0
  139. data/samples/navi/components/dom_core.xpt +0 -0
  140. data/samples/navi/components/dom_css.xpt +0 -0
  141. data/samples/navi/components/dom_events.xpt +0 -0
  142. data/samples/navi/components/dom_html.xpt +0 -0
  143. data/samples/navi/components/dom_loadsave.xpt +0 -0
  144. data/samples/navi/components/dom_range.xpt +0 -0
  145. data/samples/navi/components/dom_sidebar.xpt +0 -0
  146. data/samples/navi/components/dom_storage.xpt +0 -0
  147. data/samples/navi/components/dom_stylesheets.xpt +0 -0
  148. data/samples/navi/components/dom_svg.xpt +0 -0
  149. data/samples/navi/components/dom_traversal.xpt +0 -0
  150. data/samples/navi/components/dom_views.xpt +0 -0
  151. data/samples/navi/components/dom_xbl.xpt +0 -0
  152. data/samples/navi/components/dom_xpath.xpt +0 -0
  153. data/samples/navi/components/dom_xul.xpt +0 -0
  154. data/samples/navi/components/downloads.xpt +0 -0
  155. data/samples/navi/components/editor.xpt +0 -0
  156. data/samples/navi/components/embed_base.xpt +0 -0
  157. data/samples/navi/components/extensions.xpt +0 -0
  158. data/samples/navi/components/exthandler.xpt +0 -0
  159. data/samples/navi/components/fastfind.xpt +0 -0
  160. data/samples/navi/components/feeds.xpt +0 -0
  161. data/samples/navi/components/find.xpt +0 -0
  162. data/samples/navi/components/gfx.xpt +0 -0
  163. data/samples/navi/components/gksvgrenderer.xpt +0 -0
  164. data/samples/navi/components/history.xpt +0 -0
  165. data/samples/navi/components/htmlparser.xpt +0 -0
  166. data/samples/navi/components/imglib2.xpt +0 -0
  167. data/samples/navi/components/inspector.xpt +0 -0
  168. data/samples/navi/components/intl.xpt +0 -0
  169. data/samples/navi/components/intlcmpt.xpt +0 -0
  170. data/samples/navi/components/jar.xpt +0 -0
  171. data/samples/navi/components/jsconsole-clhandler.js +170 -0
  172. data/samples/navi/components/jsconsole.xpt +0 -0
  173. data/samples/navi/components/jsdservice.xpt +0 -0
  174. data/samples/navi/components/layout_base.xpt +0 -0
  175. data/samples/navi/components/layout_printing.xpt +0 -0
  176. data/samples/navi/components/layout_xul.xpt +0 -0
  177. data/samples/navi/components/layout_xul_tree.xpt +0 -0
  178. data/samples/navi/components/locale.xpt +0 -0
  179. data/samples/navi/components/lwbrk.xpt +0 -0
  180. data/samples/navi/components/mimetype.xpt +0 -0
  181. data/samples/navi/components/mozbrwsr.xpt +0 -0
  182. data/samples/navi/components/mozfind.xpt +0 -0
  183. data/samples/navi/components/necko.xpt +0 -0
  184. data/samples/navi/components/necko_about.xpt +0 -0
  185. data/samples/navi/components/necko_cache.xpt +0 -0
  186. data/samples/navi/components/necko_cookie.xpt +0 -0
  187. data/samples/navi/components/necko_data.xpt +0 -0
  188. data/samples/navi/components/necko_dns.xpt +0 -0
  189. data/samples/navi/components/necko_file.xpt +0 -0
  190. data/samples/navi/components/necko_ftp.xpt +0 -0
  191. data/samples/navi/components/necko_http.xpt +0 -0
  192. data/samples/navi/components/necko_res.xpt +0 -0
  193. data/samples/navi/components/necko_socket.xpt +0 -0
  194. data/samples/navi/components/necko_strconv.xpt +0 -0
  195. data/samples/navi/components/necko_viewsource.xpt +0 -0
  196. data/samples/navi/components/nsCloseAllWindows.js +143 -0
  197. data/samples/navi/components/nsDefaultCLH.js +231 -0
  198. data/samples/navi/components/nsDictionary.js +148 -0
  199. data/samples/navi/components/nsExtensionManager.js +8497 -0
  200. data/samples/navi/components/nsHelperAppDlg.js +990 -0
  201. data/samples/navi/components/nsInterfaceInfoToIDL.js +590 -0
  202. data/samples/navi/components/nsKillAll.js +200 -0
  203. data/samples/navi/components/nsPostUpdateWin.js +711 -0
  204. data/samples/navi/components/nsProgressDialog.js +949 -0
  205. data/samples/navi/components/nsProxyAutoConfig.js +396 -0
  206. data/samples/navi/components/nsResetPref.js +175 -0
  207. data/samples/navi/components/nsURLFormatter.js +179 -0
  208. data/samples/navi/components/nsUpdateService.js +3074 -0
  209. data/samples/navi/components/nsXULAppInstall.js +301 -0
  210. data/samples/navi/components/nsXmlRpcClient.js +1038 -0
  211. data/samples/navi/components/oji.xpt +0 -0
  212. data/samples/navi/components/passwordmgr.xpt +0 -0
  213. data/samples/navi/components/pipboot.xpt +0 -0
  214. data/samples/navi/components/pipnss.xpt +0 -0
  215. data/samples/navi/components/plugin.xpt +0 -0
  216. data/samples/navi/components/pref.xpt +0 -0
  217. data/samples/navi/components/prefetch.xpt +0 -0
  218. data/samples/navi/components/profile.xpt +0 -0
  219. data/samples/navi/components/progressDlg.xpt +0 -0
  220. data/samples/navi/components/proxyObject.xpt +0 -0
  221. data/samples/navi/components/rdf.xpt +0 -0
  222. data/samples/navi/components/satchel.xpt +0 -0
  223. data/samples/navi/components/saxparser.xpt +0 -0
  224. data/samples/navi/components/shistory.xpt +0 -0
  225. data/samples/navi/components/storage.xpt +0 -0
  226. data/samples/navi/components/toolkitprofile.xpt +0 -0
  227. data/samples/navi/components/transformiix.dll +0 -0
  228. data/samples/navi/components/txmgr.xpt +0 -0
  229. data/samples/navi/components/txtsvc.xpt +0 -0
  230. data/samples/navi/components/uconv.xpt +0 -0
  231. data/samples/navi/components/unicharutil.xpt +0 -0
  232. data/samples/navi/components/universalchardet.dll +0 -0
  233. data/samples/navi/components/update.xpt +0 -0
  234. data/samples/navi/components/uriloader.xpt +0 -0
  235. data/samples/navi/components/urlformatter.xpt +0 -0
  236. data/samples/navi/components/webBrowser_core.xpt +0 -0
  237. data/samples/navi/components/webbrowserpersist.xpt +0 -0
  238. data/samples/navi/components/webshell_idls.xpt +0 -0
  239. data/samples/navi/components/websrvcs.dll +0 -0
  240. data/samples/navi/components/websrvcs.xpt +0 -0
  241. data/samples/navi/components/widget.xpt +0 -0
  242. data/samples/navi/components/windowds.xpt +0 -0
  243. data/samples/navi/components/windowwatcher.xpt +0 -0
  244. data/samples/navi/components/xml-rpc.xpt +0 -0
  245. data/samples/navi/components/xmlextras.dll +0 -0
  246. data/samples/navi/components/xpcom_base.xpt +0 -0
  247. data/samples/navi/components/xpcom_components.xpt +0 -0
  248. data/samples/navi/components/xpcom_ds.xpt +0 -0
  249. data/samples/navi/components/xpcom_io.xpt +0 -0
  250. data/samples/navi/components/xpcom_obsolete.xpt +0 -0
  251. data/samples/navi/components/xpcom_thread.xpt +0 -0
  252. data/samples/navi/components/xpcom_xpti.xpt +0 -0
  253. data/samples/navi/components/xpconnect.xpt +0 -0
  254. data/samples/navi/components/xpinstall.xpt +0 -0
  255. data/samples/navi/components/xpti.dat +1424 -0
  256. data/samples/navi/components/xulapp.xpt +0 -0
  257. data/samples/navi/components/xulapp_setup.xpt +0 -0
  258. data/samples/navi/components/xuldoc.xpt +0 -0
  259. data/samples/navi/components/xulrunner.xpt +0 -0
  260. data/samples/navi/components/xultmpl.xpt +0 -0
  261. data/samples/navi/components/xulutil.dll +0 -0
  262. data/samples/navi/controlsNaviMask.png +0 -0
  263. data/samples/navi/greprefs/all.js +1344 -0
  264. data/samples/navi/greprefs/security-prefs.js +69 -0
  265. data/samples/navi/greprefs/xpinstall.js +2 -0
  266. data/samples/navi/navi_demo.rb +207 -0
  267. data/samples/navi/plugins/NPSWF32.dll +0 -0
  268. data/samples/navi/plugins/flashplayer.xpt +0 -0
  269. data/samples/navi/plugins/npnul32.dll +0 -0
  270. data/samples/navi/plugins.cfg +10 -0
  271. data/samples/navi/res/EditorOverride.css +359 -0
  272. data/samples/navi/res/Thumbs.db +0 -0
  273. data/samples/navi/res/arrow.gif +0 -0
  274. data/samples/navi/res/arrowd.gif +0 -0
  275. data/samples/navi/res/bloatcycle.html +40 -0
  276. data/samples/navi/res/broken-image.gif +0 -0
  277. data/samples/navi/res/charsetData.properties +199 -0
  278. data/samples/navi/res/charsetalias.properties +517 -0
  279. data/samples/navi/res/cmessage.txt +1 -0
  280. data/samples/navi/res/dtd/xhtml11.dtd +300 -0
  281. data/samples/navi/res/entityTables/html40Latin1.properties +146 -0
  282. data/samples/navi/res/entityTables/html40Special.properties +69 -0
  283. data/samples/navi/res/entityTables/html40Symbols.properties +164 -0
  284. data/samples/navi/res/entityTables/htmlEntityVersions.properties +50 -0
  285. data/samples/navi/res/entityTables/transliterate.properties +2367 -0
  286. data/samples/navi/res/fonts/fontEncoding.properties +127 -0
  287. data/samples/navi/res/fonts/fontNameMap.properties +134 -0
  288. data/samples/navi/res/forms.css +531 -0
  289. data/samples/navi/res/grabber.gif +0 -0
  290. data/samples/navi/res/hiddenWindow.html +1 -0
  291. data/samples/navi/res/html/Thumbs.db +0 -0
  292. data/samples/navi/res/html/gopher-audio.gif +0 -0
  293. data/samples/navi/res/html/gopher-binary.gif +0 -0
  294. data/samples/navi/res/html/gopher-find.gif +0 -0
  295. data/samples/navi/res/html/gopher-image.gif +0 -0
  296. data/samples/navi/res/html/gopher-menu.gif +0 -0
  297. data/samples/navi/res/html/gopher-movie.gif +0 -0
  298. data/samples/navi/res/html/gopher-sound.gif +0 -0
  299. data/samples/navi/res/html/gopher-telnet.gif +0 -0
  300. data/samples/navi/res/html/gopher-text.gif +0 -0
  301. data/samples/navi/res/html/gopher-unknown.gif +0 -0
  302. data/samples/navi/res/html.css +478 -0
  303. data/samples/navi/res/langGroups.properties +236 -0
  304. data/samples/navi/res/language.properties +259 -0
  305. data/samples/navi/res/loading-image.gif +0 -0
  306. data/samples/navi/res/quirk.css +282 -0
  307. data/samples/navi/res/samples/Anieyes.gif +0 -0
  308. data/samples/navi/res/samples/Thumbs.db +0 -0
  309. data/samples/navi/res/samples/aform.css +69 -0
  310. data/samples/navi/res/samples/beeptest.html +18 -0
  311. data/samples/navi/res/samples/bform.css +45 -0
  312. data/samples/navi/res/samples/bg.jpg +0 -0
  313. data/samples/navi/res/samples/cform.css +40 -0
  314. data/samples/navi/res/samples/checkboxTest.xul +47 -0
  315. data/samples/navi/res/samples/demoform.css +97 -0
  316. data/samples/navi/res/samples/find.html +97 -0
  317. data/samples/navi/res/samples/gear1.gif +0 -0
  318. data/samples/navi/res/samples/image_props.html +58 -0
  319. data/samples/navi/res/samples/mozform.css +256 -0
  320. data/samples/navi/res/samples/printsetup.html +175 -0
  321. data/samples/navi/res/samples/raptor.jpg +0 -0
  322. data/samples/navi/res/samples/rock_gra.gif +0 -0
  323. data/samples/navi/res/samples/scrollbarTest1.xul +66 -0
  324. data/samples/navi/res/samples/scrollbarTest2.xul +19 -0
  325. data/samples/navi/res/samples/sliderTest1.xul +14 -0
  326. data/samples/navi/res/samples/soundtest.html +20 -0
  327. data/samples/navi/res/samples/test.wav +0 -0
  328. data/samples/navi/res/samples/test0.html +220 -0
  329. data/samples/navi/res/samples/test1.html +84 -0
  330. data/samples/navi/res/samples/test10.html +16 -0
  331. data/samples/navi/res/samples/test11.html +42 -0
  332. data/samples/navi/res/samples/test12.html +79 -0
  333. data/samples/navi/res/samples/test13.html +126 -0
  334. data/samples/navi/res/samples/test14.html +5 -0
  335. data/samples/navi/res/samples/test15.html +5 -0
  336. data/samples/navi/res/samples/test16.html +124 -0
  337. data/samples/navi/res/samples/test2.html +41 -0
  338. data/samples/navi/res/samples/test3.html +126 -0
  339. data/samples/navi/res/samples/test4.html +335 -0
  340. data/samples/navi/res/samples/test5.html +199 -0
  341. data/samples/navi/res/samples/test6.html +335 -0
  342. data/samples/navi/res/samples/test7.html +11 -0
  343. data/samples/navi/res/samples/test8-1.html +66 -0
  344. data/samples/navi/res/samples/test8.html +662 -0
  345. data/samples/navi/res/samples/test8dom.html +64 -0
  346. data/samples/navi/res/samples/test8sca.html +308 -0
  347. data/samples/navi/res/samples/test8siz.html +224 -0
  348. data/samples/navi/res/samples/test8tab.html +9 -0
  349. data/samples/navi/res/samples/test9.html +12 -0
  350. data/samples/navi/res/samples/test9a.html +39 -0
  351. data/samples/navi/res/samples/test9b.html +16 -0
  352. data/samples/navi/res/samples/test_ed.html +5 -0
  353. data/samples/navi/res/samples/test_form.html +34 -0
  354. data/samples/navi/res/samples/test_gfx.html +75 -0
  355. data/samples/navi/res/samples/test_lbox.html +100 -0
  356. data/samples/navi/res/samples/test_pr.html +87 -0
  357. data/samples/navi/res/samples/test_weight.html +45 -0
  358. data/samples/navi/res/samples/toolbarTest1.xul +51 -0
  359. data/samples/navi/res/samples/treeTest1.css +62 -0
  360. data/samples/navi/res/samples/treeTest1.xul +110 -0
  361. data/samples/navi/res/samples/xulTest.css +130 -0
  362. data/samples/navi/res/svg.css +64 -0
  363. data/samples/navi/res/table-add-column-after-active.gif +0 -0
  364. data/samples/navi/res/table-add-column-after-hover.gif +0 -0
  365. data/samples/navi/res/table-add-column-after.gif +0 -0
  366. data/samples/navi/res/table-add-column-before-active.gif +0 -0
  367. data/samples/navi/res/table-add-column-before-hover.gif +0 -0
  368. data/samples/navi/res/table-add-column-before.gif +0 -0
  369. data/samples/navi/res/table-add-row-after-active.gif +0 -0
  370. data/samples/navi/res/table-add-row-after-hover.gif +0 -0
  371. data/samples/navi/res/table-add-row-after.gif +0 -0
  372. data/samples/navi/res/table-add-row-before-active.gif +0 -0
  373. data/samples/navi/res/table-add-row-before-hover.gif +0 -0
  374. data/samples/navi/res/table-add-row-before.gif +0 -0
  375. data/samples/navi/res/table-remove-column-active.gif +0 -0
  376. data/samples/navi/res/table-remove-column-hover.gif +0 -0
  377. data/samples/navi/res/table-remove-column.gif +0 -0
  378. data/samples/navi/res/table-remove-row-active.gif +0 -0
  379. data/samples/navi/res/table-remove-row-hover.gif +0 -0
  380. data/samples/navi/res/table-remove-row.gif +0 -0
  381. data/samples/navi/res/throbber/Thumbs.db +0 -0
  382. data/samples/navi/res/throbber/anim.gif +0 -0
  383. data/samples/navi/res/throbber/anims00.gif +0 -0
  384. data/samples/navi/res/throbber/anims01.gif +0 -0
  385. data/samples/navi/res/throbber/anims02.gif +0 -0
  386. data/samples/navi/res/throbber/anims03.gif +0 -0
  387. data/samples/navi/res/throbber/anims04.gif +0 -0
  388. data/samples/navi/res/throbber/anims05.gif +0 -0
  389. data/samples/navi/res/throbber/anims06.gif +0 -0
  390. data/samples/navi/res/throbber/anims07.gif +0 -0
  391. data/samples/navi/res/throbber/anims08.gif +0 -0
  392. data/samples/navi/res/throbber/anims09.gif +0 -0
  393. data/samples/navi/res/throbber/anims10.gif +0 -0
  394. data/samples/navi/res/throbber/anims11.gif +0 -0
  395. data/samples/navi/res/throbber/anims12.gif +0 -0
  396. data/samples/navi/res/throbber/anims13.gif +0 -0
  397. data/samples/navi/res/throbber/anims14.gif +0 -0
  398. data/samples/navi/res/throbber/anims15.gif +0 -0
  399. data/samples/navi/res/throbber/anims16.gif +0 -0
  400. data/samples/navi/res/throbber/anims17.gif +0 -0
  401. data/samples/navi/res/throbber/anims18.gif +0 -0
  402. data/samples/navi/res/throbber/anims19.gif +0 -0
  403. data/samples/navi/res/throbber/anims20.gif +0 -0
  404. data/samples/navi/res/throbber/anims21.gif +0 -0
  405. data/samples/navi/res/throbber/anims22.gif +0 -0
  406. data/samples/navi/res/throbber/anims23.gif +0 -0
  407. data/samples/navi/res/throbber/anims24.gif +0 -0
  408. data/samples/navi/res/throbber/anims25.gif +0 -0
  409. data/samples/navi/res/throbber/anims26.gif +0 -0
  410. data/samples/navi/res/throbber/anims27.gif +0 -0
  411. data/samples/navi/res/throbber/anims28.gif +0 -0
  412. data/samples/navi/res/throbber/anims29.gif +0 -0
  413. data/samples/navi/res/ua.css +235 -0
  414. data/samples/navi/res/viewer.properties +1 -0
  415. data/samples/navi/res/viewsource.css +118 -0
  416. data/samples/navi/res/wincharset.properties +55 -0
  417. data/samples/navi/resources.cfg +14 -0
  418. data/samples/navi/testNaviMask.png +0 -0
  419. data/samples/ogre.cfg +8 -0
  420. data/samples/plugins.cfg +11 -0
  421. data/samples/quake3settings.cfg +2 -0
  422. data/samples/render_run_log.5796 +891 -0
  423. data/samples/render_to_texture.rb +161 -0
  424. data/samples/resources.cfg +16 -0
  425. data/samples/sky_box.rb +107 -0
  426. data/samples/sky_dome.rb +86 -0
  427. data/samples/sky_plane.rb +27 -0
  428. data/samples/smoke.rb +23 -0
  429. data/samples/work/cube_mapping.rb +686 -0
  430. 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
+ }