From deea787c2efbb9c89caec8d9efc023ffafe75613 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Sat, 10 Feb 2018 04:00:58 -0500 Subject: Import Tycho's Add-on Manager --- .../en-US/chrome/mozapps/extensions/about.dtd | 9 + .../en-US/chrome/mozapps/extensions/blocklist.dtd | 17 + .../en-US/chrome/mozapps/extensions/extensions.dtd | 236 + .../mozapps/extensions/extensions.properties | 177 + .../en-US/chrome/mozapps/extensions/newaddon.dtd | 15 + .../chrome/mozapps/extensions/newaddon.properties | 10 + .../chrome/mozapps/extensions/selectAddons.dtd | 49 + .../mozapps/extensions/selectAddons.properties | 21 + .../en-US/chrome/mozapps/extensions/update.dtd | 65 + .../chrome/mozapps/extensions/update.properties | 21 + .../chrome/mozapps/extensions/xpinstallConfirm.dtd | 13 + .../mozapps/extensions/xpinstallConfirm.properties | 16 + toolkit/mozapps/extensions/AddonManager.jsm | 3027 ++++++++ toolkit/mozapps/extensions/AddonPathService.cpp | 223 + toolkit/mozapps/extensions/AddonPathService.h | 55 + .../mozapps/extensions/ChromeManifestParser.jsm | 159 + toolkit/mozapps/extensions/DeferredSave.jsm | 274 + .../mozapps/extensions/LightweightThemeManager.jsm | 804 ++ toolkit/mozapps/extensions/addonManager.js | 204 + toolkit/mozapps/extensions/amContentHandler.js | 100 + toolkit/mozapps/extensions/amIAddonManager.idl | 29 + toolkit/mozapps/extensions/amIAddonPathService.idl | 29 + .../mozapps/extensions/amIWebInstallListener.idl | 134 + toolkit/mozapps/extensions/amIWebInstaller.idl | 82 + toolkit/mozapps/extensions/amInstallTrigger.js | 230 + toolkit/mozapps/extensions/amWebInstallListener.js | 342 + .../extensions/content/OpenH264-license.txt | 59 + toolkit/mozapps/extensions/content/about.js | 97 + toolkit/mozapps/extensions/content/about.xul | 57 + toolkit/mozapps/extensions/content/blocklist.css | 11 + toolkit/mozapps/extensions/content/blocklist.js | 72 + toolkit/mozapps/extensions/content/blocklist.xml | 58 + toolkit/mozapps/extensions/content/blocklist.xul | 46 + toolkit/mozapps/extensions/content/eula.js | 21 + toolkit/mozapps/extensions/content/eula.xul | 35 + toolkit/mozapps/extensions/content/extensions.css | 288 + toolkit/mozapps/extensions/content/extensions.js | 3659 +++++++++ toolkit/mozapps/extensions/content/extensions.xml | 2108 ++++++ toolkit/mozapps/extensions/content/extensions.xul | 689 ++ toolkit/mozapps/extensions/content/gmpPrefs.xul | 8 + toolkit/mozapps/extensions/content/list.js | 165 + toolkit/mozapps/extensions/content/list.xul | 44 + toolkit/mozapps/extensions/content/newaddon.js | 129 + toolkit/mozapps/extensions/content/newaddon.xul | 66 + toolkit/mozapps/extensions/content/pluginPrefs.xul | 20 + .../mozapps/extensions/content/selectAddons.css | 22 + toolkit/mozapps/extensions/content/selectAddons.js | 343 + .../mozapps/extensions/content/selectAddons.xml | 235 + .../mozapps/extensions/content/selectAddons.xul | 124 + toolkit/mozapps/extensions/content/setting.xml | 508 ++ toolkit/mozapps/extensions/content/update.js | 663 ++ toolkit/mozapps/extensions/content/update.xul | 196 + toolkit/mozapps/extensions/content/updateinfo.xsl | 41 + .../extensions/content/xpinstallConfirm.css | 8 + .../mozapps/extensions/content/xpinstallConfirm.js | 196 + .../extensions/content/xpinstallConfirm.xul | 37 + .../mozapps/extensions/content/xpinstallItem.xml | 51 + toolkit/mozapps/extensions/extensions.manifest | 20 + .../mozapps/extensions/internal/AddonLogging.jsm | 180 + .../extensions/internal/AddonRepository.jsm | 2015 +++++ .../internal/AddonRepository_SQLiteMigrator.jsm | 518 ++ .../extensions/internal/AddonUpdateChecker.jsm | 772 ++ toolkit/mozapps/extensions/internal/Content.js | 31 + .../mozapps/extensions/internal/GMPProvider.jsm | 606 ++ .../internal/LightweightThemeImageOptimizer.jsm | 198 + .../mozapps/extensions/internal/PluginProvider.jsm | 560 ++ .../internal/SpellCheckDictionaryBootstrap.js | 17 + .../mozapps/extensions/internal/XPIProvider.jsm | 7863 ++++++++++++++++++++ .../extensions/internal/XPIProviderUtils.js | 1481 ++++ toolkit/mozapps/extensions/internal/moz.build | 39 + toolkit/mozapps/extensions/jar.mn | 37 + toolkit/mozapps/extensions/moz.build | 57 + toolkit/mozapps/extensions/nsBlocklistService.js | 1478 ++++ .../extensions/test/AddonManagerTesting.jsm | 105 + toolkit/mozapps/extensions/test/Makefile.in | 20 + .../test/addons/blocklist_hard1_1/install.rdf | 18 + .../test/addons/blocklist_hard1_2/install.rdf | 18 + .../test/addons/blocklist_hard1_3/install.rdf | 18 + .../test/addons/blocklist_regexp1_1/install.rdf | 18 + .../test/addons/blocklist_regexp1_2/install.rdf | 18 + .../test/addons/blocklist_regexp1_3/install.rdf | 18 + .../test/addons/blocklist_soft1_1/install.rdf | 18 + .../test/addons/blocklist_soft1_2/install.rdf | 18 + .../test/addons/blocklist_soft1_3/install.rdf | 18 + .../test/addons/blocklist_soft2_1/install.rdf | 18 + .../test/addons/blocklist_soft2_2/install.rdf | 18 + .../test/addons/blocklist_soft2_3/install.rdf | 18 + .../test/addons/blocklist_soft3_1/install.rdf | 18 + .../test/addons/blocklist_soft3_2/install.rdf | 18 + .../test/addons/blocklist_soft3_3/install.rdf | 18 + .../test/addons/blocklist_soft4_1/install.rdf | 18 + .../test/addons/blocklist_soft4_2/install.rdf | 18 + .../test/addons/blocklist_soft4_3/install.rdf | 18 + .../test/addons/blocklist_soft5_1/install.rdf | 19 + .../test/addons/blocklist_soft5_2/install.rdf | 19 + .../test/addons/blocklist_soft5_3/install.rdf | 19 + .../test/addons/bootstrap_globals/bootstrap.js | 29 + .../test/addons/bootstrap_globals/install.rdf | 23 + .../extensions/test/addons/min1max1/install.rdf | 22 + .../extensions/test/addons/min1max2/install.rdf | 22 + .../extensions/test/addons/min1max3/install.rdf | 22 + .../extensions/test/addons/min1max3b/install.rdf | 22 + .../test/addons/override1x2-1x3/install.rdf | 23 + .../test/addons/test_AddonRepository_1/install.rdf | 33 + .../test/addons/test_AddonRepository_2/install.rdf | 23 + .../test/addons/test_AddonRepository_3/icon.png | 1 + .../test/addons/test_AddonRepository_3/install.rdf | 23 + .../test/addons/test_AddonRepository_3/preview.png | 1 + .../test/addons/test_bootstrap1_1/bootstrap.js | 32 + .../test/addons/test_bootstrap1_1/install.rdf | 28 + .../test/addons/test_bootstrap1_1/version.jsm | 3 + .../test/addons/test_bootstrap1_2/bootstrap.js | 31 + .../test/addons/test_bootstrap1_2/install.rdf | 24 + .../test/addons/test_bootstrap1_2/version.jsm | 3 + .../test/addons/test_bootstrap1_3/bootstrap.js | 31 + .../test/addons/test_bootstrap1_3/install.rdf | 24 + .../test/addons/test_bootstrap1_3/version.jsm | 3 + .../test/addons/test_bootstrap1_4/install.rdf | 23 + .../test/addons/test_bootstrap2_1/bootstrap.js | 17 + .../test/addons/test_bootstrap2_1/install.rdf | 28 + .../test/addons/test_bug299716_2/install.rdf | 30 + .../test/addons/test_bug299716_a_1/install.rdf | 21 + .../test/addons/test_bug299716_a_2/install.rdf | 21 + .../test/addons/test_bug299716_b_1/install.rdf | 20 + .../test/addons/test_bug299716_b_2/install.rdf | 20 + .../test/addons/test_bug299716_c_1/install.rdf | 30 + .../test/addons/test_bug299716_c_2/install.rdf | 30 + .../test/addons/test_bug299716_d_1/install.rdf | 30 + .../test/addons/test_bug299716_d_2/install.rdf | 30 + .../test/addons/test_bug299716_e_1/install.rdf | 30 + .../test/addons/test_bug299716_e_2/install.rdf | 30 + .../test/addons/test_bug299716_f_1/install.rdf | 30 + .../test/addons/test_bug299716_f_2/install.rdf | 30 + .../test/addons/test_bug299716_g_1/install.rdf | 21 + .../test/addons/test_bug299716_g_2/install.rdf | 21 + .../test/addons/test_bug324121_1/install.rdf | 25 + .../test/addons/test_bug324121_2/install.rdf | 25 + .../test/addons/test_bug324121_3/install.rdf | 25 + .../test/addons/test_bug324121_4/install.rdf | 25 + .../test/addons/test_bug324121_5/install.rdf | 25 + .../test/addons/test_bug324121_6/install.rdf | 25 + .../test/addons/test_bug324121_7/install.rdf | 25 + .../test/addons/test_bug324121_8/install.rdf | 25 + .../test/addons/test_bug324121_9/install.rdf | 25 + .../test/addons/test_bug335238_1/install.rdf | 22 + .../test/addons/test_bug335238_2/install.rdf | 30 + .../test/addons/test_bug335238_3/install.rdf | 30 + .../test/addons/test_bug335238_4/install.rdf | 30 + .../test/addons/test_bug371495/install.rdf | 26 + .../test/addons/test_bug394300_1/install.rdf | 22 + .../test/addons/test_bug394300_2/install.rdf | 22 + .../test/addons/test_bug397778/install.rdf | 78 + .../test/addons/test_bug425657/install.rdf | 17 + .../test/addons/test_bug470377_1/install.rdf | 17 + .../test/addons/test_bug470377_2/install.rdf | 17 + .../test/addons/test_bug470377_3/install.rdf | 17 + .../test/addons/test_bug470377_4/install.rdf | 17 + .../test/addons/test_bug470377_5/install.rdf | 17 + .../test/addons/test_bug521905/install.rdf | 22 + .../test/addons/test_bug567173/install.rdf | 22 + .../test/addons/test_bug567184/bootstrap.js | 7 + .../test/addons/test_bug567184/install.rdf | 24 + .../test/addons/test_bug587088_1/install.rdf | 22 + .../test/addons/test_bug587088_1/testfile | 1 + .../test/addons/test_bug587088_1/testfile1 | 0 .../test/addons/test_bug587088_2/install.rdf | 22 + .../test/addons/test_bug587088_2/testfile | 1 + .../test/addons/test_bug587088_2/testfile2 | 0 .../test/addons/test_bug594058/directory/file1 | 0 .../test/addons/test_bug594058/install.rdf | 21 + .../test/addons/test_bug595573/install.rdf | 24 + .../test/addons/test_bug655254/install.rdf | 18 + .../test/addons/test_bug655254_2/bootstrap.js | 9 + .../test/addons/test_bug655254_2/install.rdf | 19 + .../test/addons/test_bug659772/install.rdf | 24 + .../test/addons/test_bug675371/chrome.manifest | 1 + .../test/addons/test_bug675371/install.rdf | 24 + .../extensions/test/addons/test_bug675371/test.js | 1 + .../test/addons/test_bug740612_1/bootstrap.js | 1 + .../test/addons/test_bug740612_1/install.rdf | 24 + .../test/addons/test_bug740612_2/bootstrap.js | 23 + .../test/addons/test_bug740612_2/install.rdf | 24 + .../test/addons/test_bug757663/install.rdf | 24 + .../test/addons/test_cacheflush1/install.rdf | 22 + .../test/addons/test_cacheflush2/install.rdf | 23 + .../addons/test_chromemanifest_1/chrome.manifest | 6 + .../test/addons/test_chromemanifest_1/install.rdf | 23 + .../addons/test_chromemanifest_2/chrome.manifest | 7 + .../test/addons/test_chromemanifest_2/install.rdf | 24 + .../addons/test_chromemanifest_3/chrome.manifest | 9 + .../test/addons/test_chromemanifest_3/inner.jar | Bin 0 -> 180 bytes .../test/addons/test_chromemanifest_3/install.rdf | 24 + .../addons/test_chromemanifest_4/chrome.manifest | 6 + .../components/components.manifest | 2 + .../components/other/something.manifest | 1 + .../test/addons/test_chromemanifest_4/install.rdf | 24 + .../addons/test_chromemanifest_5/chrome.manifest | 7 + .../test/addons/test_chromemanifest_5/install.rdf | 24 + .../addons/test_chromemanifest_6/chrome.manifest | 1 + .../test/addons/test_chromemanifest_6/install.rdf | 24 + .../test/addons/test_data_directory/install.rdf | 22 + .../test/addons/test_db_sanity_1_1/install.rdf | 58 + .../test/addons/test_db_sanity_1_2/install.rdf | 59 + .../addons/test_dictionary/dictionaries/ab-CD.dic | 2 + .../test/addons/test_dictionary/install.rdf | 25 + .../test_dictionary_2/dictionaries/ab-CD.dic | 2 + .../test/addons/test_dictionary_2/install.rdf | 24 + .../test/addons/test_dictionary_3/install.rdf | 25 + .../test/addons/test_dictionary_4/install.rdf | 24 + .../test/addons/test_dictionary_5/install.rdf | 25 + .../test/addons/test_distribution1_2/install.rdf | 23 + .../test/addons/test_experiment1/install.rdf | 16 + .../test/addons/test_filepointer/install.rdf | 22 + .../test/addons/test_getresource/icon.png | 1 + .../test/addons/test_getresource/install.rdf | 23 + .../addons/test_getresource/subdir/subfile.txt | 1 + .../extensions/test/addons/test_install1/icon.png | 1 + .../test/addons/test_install1/icon64.png | 1 + .../test/addons/test_install1/install.rdf | 24 + .../test/addons/test_install2_1/icon.png | 1 + .../test/addons/test_install2_1/install.rdf | 24 + .../test/addons/test_install2_2/install.rdf | 24 + .../test/addons/test_install3/install.rdf | 27 + .../test/addons/test_install4/addon4.xpi | Bin 0 -> 509 bytes .../test/addons/test_install4/addon5.jar | Bin 0 -> 512 bytes .../test/addons/test_install4/addon6.xpi | Bin 0 -> 512 bytes .../test/addons/test_install4/addon7.jar | Bin 0 -> 512 bytes .../test/addons/test_install4/badaddon.jar | 1 + .../test/addons/test_install4/badaddon.xpi | 1 + .../extensions/test/addons/test_install4/icon.png | 1 + .../test/addons/test_install4/install.rdf | 10 + .../test/addons/test_install5/chrome.manifest | 1 + .../test/addons/test_install5/install.rdf | 26 + .../test/addons/test_install6/install.rdf | 24 + .../test/addons/test_jetpack/bootstrap.js | 17 + .../test/addons/test_jetpack/harness-options.json | 1 + .../test/addons/test_jetpack/install.rdf | 28 + .../test/addons/test_langpack/chrome.manifest | 1 + .../test/addons/test_langpack/install.rdf | 23 + .../extensions/test/addons/test_locale/install.rdf | 61 + .../test/addons/test_locked2_5/install.rdf | 23 + .../test/addons/test_locked2_6/install.rdf | 23 + .../test/addons/test_migrate4_6/install.rdf | 23 + .../test/addons/test_migrate4_7/install.rdf | 23 + .../test/addons/test_migrate6/install.rdf | 23 + .../test/addons/test_migrate7/install.rdf | 24 + .../test/addons/test_migrate8/chrome.manifest | 6 + .../test/addons/test_migrate8/install.rdf | 24 + .../test/addons/test_migrate9/install.rdf | 26 + .../extensions/test/addons/test_theme/install.rdf | 26 + .../extensions/test/addons/test_theme/preview.png | 1 + .../test/addons/test_undoincompatible/bootstrap.js | 1 + .../test/addons/test_undoincompatible/install.rdf | 28 + .../test/addons/test_undouninstall1/bootstrap.js | 1 + .../test/addons/test_undouninstall1/install.rdf | 28 + .../extensions/test/addons/test_update/install.rdf | 23 + .../test/addons/test_update12/install.rdf | 23 + .../test/addons/test_update8/install.rdf | 23 + .../test/addons/test_updateid2_2/install.rdf | 24 + .../test/addons/test_updateid2_5/install.rdf | 24 + .../test/addons/test_updateid3_3/bootstrap.js | 21 + .../test/addons/test_updateid3_3/install.rdf | 25 + .../test/addons/test_updateid4_4/bootstrap.js | 21 + .../test/addons/test_updateid4_4/install.rdf | 25 + .../test/addons/upgradeable1x2-3_1/install.rdf | 22 + .../test/addons/upgradeable1x2-3_2/install.rdf | 22 + .../mozapps/extensions/test/browser/Makefile.in | 19 + .../extensions/test/browser/addon_about.xul | 6 + .../extensions/test/browser/addon_prefs.xul | 6 + .../browser/addons/browser_bug557956_1/install.rdf | 23 + .../addons/browser_bug557956_10/install.rdf | 23 + .../browser/addons/browser_bug557956_2/install.rdf | 23 + .../browser/addons/browser_bug557956_3/install.rdf | 23 + .../browser/addons/browser_bug557956_4/install.rdf | 23 + .../browser/addons/browser_bug557956_5/install.rdf | 23 + .../browser/addons/browser_bug557956_6/install.rdf | 23 + .../browser/addons/browser_bug557956_7/install.rdf | 23 + .../addons/browser_bug557956_8_1/install.rdf | 23 + .../addons/browser_bug557956_9_1/install.rdf | 23 + .../browser/addons/browser_bug567127_1/install.rdf | 22 + .../browser/addons/browser_bug567127_2/install.rdf | 22 + .../browser/addons/browser_bug596336_1/install.rdf | 23 + .../browser/addons/browser_bug596336_2/install.rdf | 23 + .../browser/addons/browser_dragdrop1/install.rdf | 22 + .../browser/addons/browser_dragdrop2/install.rdf | 22 + .../browser/addons/browser_experiment1/install.rdf | 16 + .../addons/browser_inlinesettings1/bootstrap.js | 8 + .../addons/browser_inlinesettings1/install.rdf | 19 + .../addons/browser_inlinesettings1/options.xul | 20 + .../browser_inlinesettings1_custom/binding.xml | 19 + .../browser_inlinesettings1_custom/bootstrap.js | 8 + .../browser_inlinesettings1_custom/chrome.manifest | 2 + .../browser_inlinesettings1_custom/install.rdf | 19 + .../browser_inlinesettings1_custom/options.xul | 5 + .../browser_inlinesettings1_custom/string.dtd | 1 + .../browser_inlinesettings1_info/bootstrap.js | 8 + .../browser_inlinesettings1_info/install.rdf | 20 + .../browser_inlinesettings1_info/options.xul | 19 + .../browser/addons/browser_install1_1/install.rdf | 24 + .../browser/addons/browser_install1_2/install.rdf | 22 + .../browser/addons/browser_installssl/install.rdf | 22 + .../browser/addons/browser_searching/bootstrap.js | 9 + .../browser/addons/browser_searching/install.rdf | 25 + .../browser_select_compatoverrides_1/install.rdf | 23 + .../extensions/test/browser/blockNoPlugins.xml | 7 + .../extensions/test/browser/blockPluginHard.xml | 11 + .../extensions/test/browser/browser-common.ini | 78 + .../extensions/test/browser/browser-window.ini | 4 + .../mozapps/extensions/test/browser/browser.ini | 53 + .../extensions/test/browser/browser_CTP_plugins.js | 234 + .../extensions/test/browser/browser_about.js | 84 + .../browser/browser_addonrepository_performance.js | 99 + .../extensions/test/browser/browser_bug523784.js | 120 + .../extensions/test/browser/browser_bug557943.js | 80 + .../extensions/test/browser/browser_bug557956.js | 518 ++ .../extensions/test/browser/browser_bug557956.rdf | 220 + .../extensions/test/browser/browser_bug557956.xml | 20 + .../test/browser/browser_bug557956_8_2.xpi | Bin 0 -> 471 bytes .../test/browser/browser_bug557956_9_2.xpi | Bin 0 -> 471 bytes .../extensions/test/browser/browser_bug562797.js | 965 +++ .../extensions/test/browser/browser_bug562854.js | 129 + .../extensions/test/browser/browser_bug562890.js | 78 + .../extensions/test/browser/browser_bug562899.js | 88 + .../extensions/test/browser/browser_bug562992.js | 70 + .../extensions/test/browser/browser_bug567127.js | 137 + .../extensions/test/browser/browser_bug567137.js | 40 + .../extensions/test/browser/browser_bug570760.js | 44 + .../extensions/test/browser/browser_bug572561.js | 99 + .../extensions/test/browser/browser_bug573062.js | 116 + .../extensions/test/browser/browser_bug577990.js | 132 + .../extensions/test/browser/browser_bug580298.js | 111 + .../extensions/test/browser/browser_bug581076.js | 128 + .../extensions/test/browser/browser_bug586574.js | 286 + .../extensions/test/browser/browser_bug587970.js | 180 + .../extensions/test/browser/browser_bug590347.js | 120 + .../extensions/test/browser/browser_bug591465.js | 512 ++ .../extensions/test/browser/browser_bug591465.xml | 35 + .../extensions/test/browser/browser_bug591663.js | 161 + .../extensions/test/browser/browser_bug593535.js | 118 + .../extensions/test/browser/browser_bug593535.xml | 34 + .../extensions/test/browser/browser_bug596336.js | 180 + .../extensions/test/browser/browser_bug608316.js | 65 + .../extensions/test/browser/browser_bug610764.js | 34 + .../extensions/test/browser/browser_bug616841.js | 21 + .../extensions/test/browser/browser_bug618502.js | 44 + .../extensions/test/browser/browser_bug679604.js | 29 + .../extensions/test/browser/browser_bug714593.js | 140 + .../test/browser/browser_cancelCompatCheck.js | 462 ++ .../browser/browser_checkAddonCompatibility.js | 34 + .../test/browser/browser_debug_button.js | 112 + .../extensions/test/browser/browser_details.js | 764 ++ .../extensions/test/browser/browser_discovery.js | 637 ++ .../test/browser/browser_discovery_install.js | 130 + .../extensions/test/browser/browser_dragdrop.js | 234 + .../extensions/test/browser/browser_eula.js | 85 + .../extensions/test/browser/browser_eula.xml | 35 + .../extensions/test/browser/browser_experiments.js | 645 ++ .../test/browser/browser_globalinformations.js | 55 + .../test/browser/browser_globalwarnings.js | 63 + .../extensions/test/browser/browser_gmpProvider.js | 401 + .../test/browser/browser_inlinesettings.js | 677 ++ .../test/browser/browser_inlinesettings_custom.js | 92 + .../test/browser/browser_inlinesettings_info.js | 569 ++ .../extensions/test/browser/browser_install.js | 312 + .../extensions/test/browser/browser_install.rdf | 27 + .../test/browser/browser_install.rdf^headers^ | 1 + .../extensions/test/browser/browser_install.xml | 34 + .../extensions/test/browser/browser_install1_3.xpi | Bin 0 -> 463 bytes .../extensions/test/browser/browser_installssl.js | 374 + .../extensions/test/browser/browser_list.js | 760 ++ .../test/browser/browser_manualupdates.js | 242 + .../test/browser/browser_metadataTimeout.js | 114 + .../extensions/test/browser/browser_newaddon.js | 186 + .../extensions/test/browser/browser_openDialog.js | 176 + .../browser/browser_plugin_enabled_state_locked.js | 125 + .../extensions/test/browser/browser_pluginprefs.js | 61 + .../extensions/test/browser/browser_purchase.js | 195 + .../extensions/test/browser/browser_purchase.xml | 180 + .../test/browser/browser_recentupdates.js | 125 + .../extensions/test/browser/browser_searching.js | 695 ++ .../extensions/test/browser/browser_searching.xml | 277 + .../test/browser/browser_searching_empty.xml | 3 + .../test/browser/browser_select_compatoverrides.js | 116 + .../browser/browser_select_compatoverrides.xml | 20 + .../test/browser/browser_select_confirm.js | 181 + .../test/browser/browser_select_selection.js | 268 + .../test/browser/browser_select_update.js | 181 + .../extensions/test/browser/browser_sorting.js | 372 + .../test/browser/browser_sorting_plugins.js | 95 + .../extensions/test/browser/browser_tabsettings.js | 100 + .../test/browser/browser_task_next_test.js | 17 + .../extensions/test/browser/browser_types.js | 473 ++ .../test/browser/browser_uninstalling.js | 1099 +++ .../extensions/test/browser/browser_updateid.js | 80 + .../extensions/test/browser/browser_updatessl.js | 370 + .../extensions/test/browser/browser_updatessl.rdf | 25 + .../test/browser/browser_updatessl.rdf^headers^ | 1 + .../extensions/test/browser/cancelCompatCheck.sjs | 43 + .../mozapps/extensions/test/browser/discovery.html | 10 + .../extensions/test/browser/discovery_frame.html | 6 + .../extensions/test/browser/discovery_install.html | 18 + toolkit/mozapps/extensions/test/browser/head.js | 1393 ++++ .../extensions/test/browser/more_options.xul | 32 + toolkit/mozapps/extensions/test/browser/moz.build | 10 + .../mozapps/extensions/test/browser/options.xul | 12 + .../extensions/test/browser/plugin_test.html | 7 + .../mozapps/extensions/test/browser/redirect.sjs | 5 + .../extensions/test/browser/releaseNotes.xhtml | 15 + .../extensions/test/mochitest/file_bug687194.xpi | Bin 0 -> 1602 bytes .../extensions/test/mochitest/file_empty.html | 2 + .../extensions/test/mochitest/mochitest.ini | 10 + .../extensions/test/mochitest/test_bug609794.html | 27 + .../extensions/test/mochitest/test_bug687194.html | 133 + .../extensions/test/mochitest/test_bug887098.html | 51 + toolkit/mozapps/extensions/test/moz.build | 20 + .../xpcshell/data/blocklistchange/addon_change.xml | 31 + .../data/blocklistchange/addon_update1.rdf | 144 + .../data/blocklistchange/addon_update2.rdf | 144 + .../data/blocklistchange/addon_update3.rdf | 144 + .../xpcshell/data/blocklistchange/app_update.xml | 62 + .../data/blocklistchange/blocklist_update1.xml | 3 + .../data/blocklistchange/blocklist_update2.xml | 26 + .../data/blocklistchange/manual_update.xml | 27 + .../test/xpcshell/data/bug455906_block.xml | 18 + .../test/xpcshell/data/bug455906_empty.xml | 7 + .../test/xpcshell/data/bug455906_start.xml | 30 + .../test/xpcshell/data/bug455906_warn.xml | 33 + .../extensions/test/xpcshell/data/corrupt.xpi | 1 + .../extensions/test/xpcshell/data/corruptfile.xpi | Bin 0 -> 633 bytes .../extensions/test/xpcshell/data/empty.xpi | Bin 0 -> 197 bytes .../test/xpcshell/data/pluginInfoURL_block.xml | 21 + .../test/xpcshell/data/test_AddonRepository.xml | 820 ++ .../xpcshell/data/test_AddonRepository_cache.xml | 182 + .../test_AddonRepository_compatmode_ignore.xml | 23 + .../test_AddonRepository_compatmode_normal.xml | 23 + .../test_AddonRepository_compatmode_strict.xml | 23 + .../xpcshell/data/test_AddonRepository_empty.xml | 3 + .../xpcshell/data/test_AddonRepository_failed.xml | 21 + .../data/test_AddonRepository_getAddonsByIDs.xml | 187 + .../test/xpcshell/data/test_backgroundupdate.rdf | 70 + .../data/test_blocklist_metadata_filters_1.xml | 21 + .../test/xpcshell/data/test_blocklist_prefs_1.xml | 28 + .../test/xpcshell/data/test_blocklist_regexp_1.xml | 20 + .../test/xpcshell/data/test_bug299716.rdf | 181 + .../test/xpcshell/data/test_bug299716_2.rdf | 23 + .../test/xpcshell/data/test_bug324121.rdf | 91 + .../test/xpcshell/data/test_bug393285.xml | 30 + .../test/xpcshell/data/test_bug394300.rdf | 159 + .../test/xpcshell/data/test_bug424262.xml | 185 + .../test/xpcshell/data/test_bug449027_app.xml | 333 + .../test/xpcshell/data/test_bug449027_toolkit.xml | 208 + .../test/xpcshell/data/test_bug468528.xml | 15 + .../xpcshell/data/test_bug470377/install_1.rdf | 17 + .../xpcshell/data/test_bug470377/install_2.rdf | 17 + .../xpcshell/data/test_bug470377/install_3.rdf | 17 + .../xpcshell/data/test_bug470377/install_4.rdf | 17 + .../xpcshell/data/test_bug470377/install_5.rdf | 17 + .../test/xpcshell/data/test_bug470377/update_1.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_2.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_3.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_4.rdf | 26 + .../test/xpcshell/data/test_bug470377/update_5.rdf | 26 + .../test/xpcshell/data/test_bug514327_1.xml | 17 + .../test/xpcshell/data/test_bug514327_2.xml | 10 + .../test/xpcshell/data/test_bug514327_3_empty.xml | 4 + .../xpcshell/data/test_bug514327_3_outdated_1.xml | 13 + .../xpcshell/data/test_bug514327_3_outdated_2.xml | 13 + .../test/xpcshell/data/test_bug526598_1.xpi | Bin 0 -> 458 bytes .../test/xpcshell/data/test_bug526598_2.xpi | Bin 0 -> 458 bytes .../test/xpcshell/data/test_bug541420.xpi | Bin 0 -> 577 bytes .../test/xpcshell/data/test_bug542391.rdf | 25 + .../test/xpcshell/data/test_bug554133.xml | 292 + .../test/xpcshell/data/test_bug619730.xml | 7 + .../test/xpcshell/data/test_bug655254.rdf | 26 + .../test/xpcshell/data/test_compatoverrides.xml | 228 + .../extensions/test/xpcshell/data/test_corrupt.rdf | 44 + .../test/xpcshell/data/test_dictionary.rdf | 65 + .../data/test_distribution2_2/bootstrap.js | 21 + .../xpcshell/data/test_distribution2_2/install.rdf | 23 + .../data/test_distribution2_2/subdir/dummy.txt | 1 + .../test_distribution2_2/subdir/subdir2/dummy2.txt | 1 + .../test/xpcshell/data/test_gfxBlacklist.xml | 154 + .../test/xpcshell/data/test_gfxBlacklist2.xml | 31 + .../test/xpcshell/data/test_gfxBlacklist_AllOS.xml | 32 + .../xpcshell/data/test_gfxBlacklist_OSVersion.xml | 32 + .../extensions/test/xpcshell/data/test_install.rdf | 63 + .../extensions/test/xpcshell/data/test_install.xml | 53 + .../extensions/test/xpcshell/data/test_migrate.rdf | 125 + .../test/xpcshell/data/test_migrate4.rdf | 46 + .../data/test_overrideblocklist/ancient.xml | 8 + .../xpcshell/data/test_overrideblocklist/new.xml | 8 + .../xpcshell/data/test_overrideblocklist/old.xml | 8 + .../test/xpcshell/data/test_pluginBlocklistCtp.xml | 26 + .../xpcshell/data/test_pluginBlocklistCtpUndo.xml | 10 + .../test/xpcshell/data/test_sourceURI.xml | 18 + .../extensions/test/xpcshell/data/test_update.rdf | 270 + .../extensions/test/xpcshell/data/test_update.xml | 26 + .../test/xpcshell/data/test_updatecheck.rdf | 419 ++ .../xpcshell/data/test_updatecompatmode_ignore.rdf | 26 + .../xpcshell/data/test_updatecompatmode_normal.rdf | 26 + .../xpcshell/data/test_updatecompatmode_strict.rdf | 26 + .../test/xpcshell/data/test_updateid.rdf | 86 + .../extensions/test/xpcshell/data/unsigned.xpi | Bin 0 -> 452 bytes .../extensions/test/xpcshell/head_addons.js | 1759 +++++ .../extensions/test/xpcshell/head_unpack.js | 2 + .../test/xpcshell/test_AddonRepository.js | 625 ++ .../test/xpcshell/test_AddonRepository_cache.js | 710 ++ .../xpcshell/test_AddonRepository_compatmode.js | 90 + .../test/xpcshell/test_ChromeManifestParser.js | 108 + .../extensions/test/xpcshell/test_DeferredSave.js | 550 ++ .../test/xpcshell/test_LightweightThemeManager.js | 514 ++ .../extensions/test/xpcshell/test_XPIStates.js | 299 + .../extensions/test/xpcshell/test_XPIcancel.js | 66 + .../test/xpcshell/test_addon_path_service.js | 38 + .../test/xpcshell/test_asyncBlocklistLoad.js | 44 + .../test/xpcshell/test_backgroundupdate.js | 122 + .../extensions/test/xpcshell/test_bad_json.js | 54 + .../extensions/test/xpcshell/test_badschema.js | 404 + .../xpcshell/test_blocklist_metadata_filters.js | 159 + .../test/xpcshell/test_blocklist_prefs.js | 159 + .../test/xpcshell/test_blocklist_regexp.js | 125 + .../test/xpcshell/test_blocklistchange.js | 1321 ++++ .../extensions/test/xpcshell/test_bootstrap.js | 1434 ++++ .../test/xpcshell/test_bootstrap_globals.js | 37 + .../test/xpcshell/test_bootstrap_resource.js | 56 + .../extensions/test/xpcshell/test_bug299716.js | 209 + .../extensions/test/xpcshell/test_bug299716_2.js | 50 + .../extensions/test/xpcshell/test_bug324121.js | 178 + .../extensions/test/xpcshell/test_bug335238.js | 181 + .../extensions/test/xpcshell/test_bug371495.js | 35 + .../extensions/test/xpcshell/test_bug384052.js | 103 + .../extensions/test/xpcshell/test_bug393285.js | 327 + .../extensions/test/xpcshell/test_bug394300.js | 56 + .../extensions/test/xpcshell/test_bug397778.js | 117 + .../extensions/test/xpcshell/test_bug406118.js | 167 + .../extensions/test/xpcshell/test_bug424262.js | 62 + .../extensions/test/xpcshell/test_bug425657.js | 27 + .../extensions/test/xpcshell/test_bug430120.js | 142 + .../extensions/test/xpcshell/test_bug449027.js | 448 ++ .../extensions/test/xpcshell/test_bug455906.js | 536 ++ .../extensions/test/xpcshell/test_bug465190.js | 39 + .../extensions/test/xpcshell/test_bug468528.js | 58 + .../extensions/test/xpcshell/test_bug470377_1.js | 49 + .../test/xpcshell/test_bug470377_1_strictcompat.js | 49 + .../extensions/test/xpcshell/test_bug470377_2.js | 49 + .../extensions/test/xpcshell/test_bug470377_3.js | 95 + .../test/xpcshell/test_bug470377_3_strictcompat.js | 94 + .../extensions/test/xpcshell/test_bug470377_4.js | 92 + .../extensions/test/xpcshell/test_bug514327_1.js | 59 + .../extensions/test/xpcshell/test_bug514327_2.js | 42 + .../extensions/test/xpcshell/test_bug514327_3.js | 166 + .../extensions/test/xpcshell/test_bug521905.js | 59 + .../extensions/test/xpcshell/test_bug526598.js | 54 + .../extensions/test/xpcshell/test_bug541420.js | 37 + .../extensions/test/xpcshell/test_bug542391.js | 486 ++ .../extensions/test/xpcshell/test_bug554133.js | 86 + .../extensions/test/xpcshell/test_bug559800.js | 71 + .../extensions/test/xpcshell/test_bug563256.js | 259 + .../extensions/test/xpcshell/test_bug564030.js | 63 + .../extensions/test/xpcshell/test_bug566626.js | 112 + .../extensions/test/xpcshell/test_bug567184.js | 53 + .../extensions/test/xpcshell/test_bug569138.js | 147 + .../extensions/test/xpcshell/test_bug570173.js | 80 + .../extensions/test/xpcshell/test_bug576735.js | 66 + .../extensions/test/xpcshell/test_bug587088.js | 174 + .../extensions/test/xpcshell/test_bug594058.js | 97 + .../extensions/test/xpcshell/test_bug595081.js | 27 + .../extensions/test/xpcshell/test_bug595573.js | 40 + .../extensions/test/xpcshell/test_bug596343.js | 86 + .../extensions/test/xpcshell/test_bug596607.js | 140 + .../extensions/test/xpcshell/test_bug616841.js | 26 + .../extensions/test/xpcshell/test_bug619730.js | 64 + .../extensions/test/xpcshell/test_bug620837.js | 145 + .../extensions/test/xpcshell/test_bug655254.js | 164 + .../extensions/test/xpcshell/test_bug659772.js | 340 + .../extensions/test/xpcshell/test_bug675371.js | 91 + .../extensions/test/xpcshell/test_bug740612.js | 40 + .../extensions/test/xpcshell/test_bug753900.js | 86 + .../extensions/test/xpcshell/test_bug757663.js | 112 + .../extensions/test/xpcshell/test_bug953156.js | 51 + .../extensions/test/xpcshell/test_cacheflush.js | 124 + .../test_checkCompatibility_themeOverride.js | 93 + .../test/xpcshell/test_checkcompatibility.js | 196 + .../extensions/test/xpcshell/test_childprocess.js | 21 + .../test/xpcshell/test_compatoverrides.js | 259 + .../extensions/test/xpcshell/test_corrupt.js | 403 + .../test/xpcshell/test_corrupt_strictcompat.js | 402 + .../extensions/test/xpcshell/test_corruptfile.js | 83 + .../extensions/test/xpcshell/test_dataDirectory.js | 50 + .../test/xpcshell/test_default_providers_pref.js | 13 + .../extensions/test/xpcshell/test_dictionary.js | 801 ++ .../extensions/test/xpcshell/test_disable.js | 194 + .../extensions/test/xpcshell/test_distribution.js | 262 + .../mozapps/extensions/test/xpcshell/test_dss.js | 824 ++ .../test/xpcshell/test_duplicateplugins.js | 185 + .../mozapps/extensions/test/xpcshell/test_error.js | 90 + .../extensions/test/xpcshell/test_experiment.js | 104 + .../extensions/test/xpcshell/test_filepointer.js | 403 + .../mozapps/extensions/test/xpcshell/test_fuel.js | 164 + .../extensions/test/xpcshell/test_general.js | 58 + .../extensions/test/xpcshell/test_getresource.js | 94 + .../test/xpcshell/test_gfxBlacklist_Device.js | 95 + .../test/xpcshell/test_gfxBlacklist_DriverNew.js | 94 + .../xpcshell/test_gfxBlacklist_Equal_DriverNew.js | 95 + .../xpcshell/test_gfxBlacklist_Equal_DriverOld.js | 95 + .../test/xpcshell/test_gfxBlacklist_Equal_OK.js | 95 + .../xpcshell/test_gfxBlacklist_GTE_DriverOld.js | 95 + .../test/xpcshell/test_gfxBlacklist_GTE_OK.js | 95 + .../xpcshell/test_gfxBlacklist_No_Comparison.js | 89 + .../test/xpcshell/test_gfxBlacklist_OK.js | 96 + .../test/xpcshell/test_gfxBlacklist_OS.js | 96 + .../xpcshell/test_gfxBlacklist_OSVersion_match.js | 96 + ...fxBlacklist_OSVersion_mismatch_DriverVersion.js | 97 + ...st_gfxBlacklist_OSVersion_mismatch_OSVersion.js | 97 + .../test/xpcshell/test_gfxBlacklist_Vendor.js | 95 + .../test/xpcshell/test_gfxBlacklist_prefs.js | 132 + .../extensions/test/xpcshell/test_gmpProvider.js | 332 + .../test/xpcshell/test_hasbinarycomponents.js | 82 + .../extensions/test/xpcshell/test_install.js | 1761 +++++ .../extensions/test/xpcshell/test_install_icons.js | 61 + .../test/xpcshell/test_install_strictcompat.js | 1654 ++++ .../extensions/test/xpcshell/test_isDebuggable.js | 36 + .../extensions/test/xpcshell/test_isReady.js | 49 + .../extensions/test/xpcshell/test_langpack.js | 339 + .../extensions/test/xpcshell/test_locale.js | 149 + .../extensions/test/xpcshell/test_locked.js | 529 ++ .../extensions/test/xpcshell/test_locked2.js | 292 + .../test/xpcshell/test_locked_strictcompat.js | 551 ++ .../extensions/test/xpcshell/test_manifest.js | 562 ++ .../test/xpcshell/test_mapURIToAddonID.js | 326 + .../test/xpcshell/test_metadata_update.js | 184 + .../extensions/test/xpcshell/test_migrate1.js | 250 + .../extensions/test/xpcshell/test_migrate2.js | 259 + .../extensions/test/xpcshell/test_migrate3.js | 239 + .../extensions/test/xpcshell/test_migrate4.js | 307 + .../extensions/test/xpcshell/test_migrate5.js | 139 + .../test/xpcshell/test_migrateAddonRepository.js | 127 + .../test/xpcshell/test_migrate_max_version.js | 103 + .../test/xpcshell/test_multiprocessCompatible.js | 118 + .../extensions/test/xpcshell/test_no_addons.js | 98 + .../xpcshell/test_onPropertyChanged_appDisabled.js | 66 + .../test/xpcshell/test_overrideblocklist.js | 200 + .../extensions/test/xpcshell/test_permissions.js | 86 + .../test/xpcshell/test_permissions_prefs.js | 74 + .../test/xpcshell/test_pluginBlocklistCtp.js | 181 + .../extensions/test/xpcshell/test_pluginInfoURL.js | 80 + .../extensions/test/xpcshell/test_pluginchange.js | 292 + .../extensions/test/xpcshell/test_plugins.js | 210 + .../test/xpcshell/test_pref_properties.js | 206 + .../test/xpcshell/test_provider_markSafe.js | 47 + .../test/xpcshell/test_provider_shutdown.js | 97 + .../test_provider_unsafe_access_shutdown.js | 61 + .../test_provider_unsafe_access_startup.js | 53 + .../extensions/test/xpcshell/test_registry.js | 151 + .../extensions/test/xpcshell/test_safemode.js | 115 + .../extensions/test/xpcshell/test_shutdown.js | 65 + .../extensions/test/xpcshell/test_sourceURI.js | 66 + .../extensions/test/xpcshell/test_startup.js | 917 +++ .../test/xpcshell/test_strictcompatibility.js | 203 + .../extensions/test/xpcshell/test_syncGUID.js | 154 + .../test/xpcshell/test_targetPlatforms.js | 146 + .../mozapps/extensions/test/xpcshell/test_theme.js | 1092 +++ .../mozapps/extensions/test/xpcshell/test_types.js | 65 + .../test/xpcshell/test_undothemeuninstall.js | 421 ++ .../extensions/test/xpcshell/test_undouninstall.js | 792 ++ .../extensions/test/xpcshell/test_uninstall.js | 216 + .../extensions/test/xpcshell/test_update.js | 1310 ++++ .../extensions/test/xpcshell/test_updateCancel.js | 142 + .../test/xpcshell/test_update_compatmode.js | 184 + .../test/xpcshell/test_update_ignorecompat.js | 98 + .../test/xpcshell/test_update_strictcompat.js | 1085 +++ .../extensions/test/xpcshell/test_updatecheck.js | 312 + .../extensions/test/xpcshell/test_updateid.js | 422 ++ .../extensions/test/xpcshell/test_upgrade.js | 206 + .../test/xpcshell/test_upgrade_strictcompat.js | 209 + .../extensions/test/xpcshell/xpcshell-shared.ini | 281 + .../extensions/test/xpcshell/xpcshell-unpack.ini | 8 + .../mozapps/extensions/test/xpcshell/xpcshell.ini | 28 + .../extensions/test/xpinstall/authRedirect.sjs | 21 + .../mozapps/extensions/test/xpinstall/browser.ini | 103 + .../extensions/test/xpinstall/browser_auth.js | 43 + .../extensions/test/xpinstall/browser_auth2.js | 46 + .../extensions/test/xpinstall/browser_auth3.js | 54 + .../extensions/test/xpinstall/browser_auth4.js | 53 + .../extensions/test/xpinstall/browser_badargs.js | 37 + .../extensions/test/xpinstall/browser_badargs2.js | 41 + .../extensions/test/xpinstall/browser_badhash.js | 33 + .../test/xpinstall/browser_badhashtype.js | 33 + .../extensions/test/xpinstall/browser_bug540558.js | 25 + .../extensions/test/xpinstall/browser_bug611242.js | 34 + .../extensions/test/xpinstall/browser_bug638292.js | 63 + .../extensions/test/xpinstall/browser_bug645699.js | 36 + .../extensions/test/xpinstall/browser_bug672485.js | 52 + .../extensions/test/xpinstall/browser_cancel.js | 62 + .../test/xpinstall/browser_concurrent_installs.js | 128 + .../extensions/test/xpinstall/browser_cookies.js | 30 + .../extensions/test/xpinstall/browser_cookies2.js | 40 + .../extensions/test/xpinstall/browser_cookies3.js | 44 + .../extensions/test/xpinstall/browser_cookies4.js | 43 + .../extensions/test/xpinstall/browser_corrupt.js | 32 + .../extensions/test/xpinstall/browser_datauri.js | 36 + .../extensions/test/xpinstall/browser_empty.js | 28 + .../extensions/test/xpinstall/browser_enabled.js | 24 + .../extensions/test/xpinstall/browser_enabled2.js | 27 + .../extensions/test/xpinstall/browser_enabled3.js | 48 + .../extensions/test/xpinstall/browser_hash.js | 34 + .../extensions/test/xpinstall/browser_hash2.js | 34 + .../extensions/test/xpinstall/browser_httphash.js | 39 + .../extensions/test/xpinstall/browser_httphash2.js | 39 + .../extensions/test/xpinstall/browser_httphash3.js | 39 + .../extensions/test/xpinstall/browser_httphash4.js | 36 + .../extensions/test/xpinstall/browser_httphash5.js | 40 + .../extensions/test/xpinstall/browser_httphash6.js | 83 + .../test/xpinstall/browser_installchrome.js | 25 + .../extensions/test/xpinstall/browser_localfile.js | 34 + .../test/xpinstall/browser_localfile2.js | 49 + .../test/xpinstall/browser_localfile3.js | 40 + .../test/xpinstall/browser_localfile4.js | 40 + .../test/xpinstall/browser_multipackage.js | 53 + .../test/xpinstall/browser_navigateaway.js | 36 + .../test/xpinstall/browser_navigateaway2.js | 34 + .../test/xpinstall/browser_navigateaway3.js | 75 + .../test/xpinstall/browser_navigateaway4.js | 44 + .../extensions/test/xpinstall/browser_offline.js | 61 + .../extensions/test/xpinstall/browser_relative.js | 49 + .../test/xpinstall/browser_signed_multiple.js | 72 + .../test/xpinstall/browser_signed_naming.js | 67 + .../test/xpinstall/browser_signed_tampered.js | 33 + .../test/xpinstall/browser_signed_trigger.js | 41 + .../test/xpinstall/browser_signed_untrusted.js | 41 + .../test/xpinstall/browser_signed_url.js | 34 + .../test/xpinstall/browser_softwareupdate.js | 25 + .../extensions/test/xpinstall/browser_switchtab.js | 49 + .../test/xpinstall/browser_trigger_redirect.js | 41 + .../test/xpinstall/browser_unsigned_trigger.js | 50 + .../xpinstall/browser_unsigned_trigger_iframe.js | 51 + .../xpinstall/browser_unsigned_trigger_xorigin.js | 38 + .../test/xpinstall/browser_unsigned_url.js | 35 + .../extensions/test/xpinstall/browser_whitelist.js | 46 + .../test/xpinstall/browser_whitelist2.js | 31 + .../test/xpinstall/browser_whitelist3.js | 28 + .../test/xpinstall/browser_whitelist4.js | 30 + .../test/xpinstall/browser_whitelist5.js | 25 + .../test/xpinstall/browser_whitelist6.js | 25 + .../test/xpinstall/browser_whitelist7.js | 32 + .../extensions/test/xpinstall/bug540558.html | 23 + .../extensions/test/xpinstall/bug638292.html | 17 + .../extensions/test/xpinstall/bug645699.html | 30 + .../test/xpinstall/concurrent_installs.html | 39 + .../extensions/test/xpinstall/cookieRedirect.sjs | 24 + .../mozapps/extensions/test/xpinstall/corrupt.xpi | 1 + .../mozapps/extensions/test/xpinstall/empty.xpi | Bin 0 -> 197 bytes .../mozapps/extensions/test/xpinstall/enabled.html | 23 + .../extensions/test/xpinstall/hashRedirect.sjs | 15 + toolkit/mozapps/extensions/test/xpinstall/head.js | 424 ++ .../extensions/test/xpinstall/incompatible.xpi | Bin 0 -> 470 bytes .../extensions/test/xpinstall/installchrome.html | 21 + .../extensions/test/xpinstall/installtrigger.html | 43 + .../test/xpinstall/installtrigger_frame.html | 29 + .../extensions/test/xpinstall/multipackage.xpi | Bin 0 -> 2976 bytes .../extensions/test/xpinstall/navigate.html | 26 + .../mozapps/extensions/test/xpinstall/redirect.sjs | 45 + .../extensions/test/xpinstall/restartless.xpi | Bin 0 -> 485 bytes .../extensions/test/xpinstall/signed-no-cn.xpi | Bin 0 -> 2241 bytes .../extensions/test/xpinstall/signed-no-o.xpi | Bin 0 -> 2247 bytes .../extensions/test/xpinstall/signed-tampered.xpi | Bin 0 -> 2260 bytes .../extensions/test/xpinstall/signed-untrusted.xpi | Bin 0 -> 2237 bytes .../mozapps/extensions/test/xpinstall/signed.xpi | Bin 0 -> 2250 bytes .../mozapps/extensions/test/xpinstall/signed2.xpi | Bin 0 -> 2938 bytes .../extensions/test/xpinstall/slowinstall.sjs | 101 + .../test/xpinstall/startsoftwareupdate.html | 19 + .../mozapps/extensions/test/xpinstall/theme.xpi | Bin 0 -> 491 bytes .../extensions/test/xpinstall/triggerredirect.html | 35 + .../mozapps/extensions/test/xpinstall/unsigned.xpi | Bin 0 -> 452 bytes .../mozapps/extensions/category-available.png | Bin 0 -> 1092 bytes .../mozapps/extensions/category-dictionaries.png | Bin 0 -> 1290 bytes .../linux/mozapps/extensions/category-discover.png | Bin 0 -> 1482 bytes .../mozapps/extensions/category-experiments.png | Bin 0 -> 822 bytes .../linux/mozapps/extensions/category-plugins.png | Bin 0 -> 1172 bytes .../linux/mozapps/extensions/category-recent.png | Bin 0 -> 2020 bytes .../linux/mozapps/extensions/category-search.png | Bin 0 -> 2600 bytes .../linux/mozapps/extensions/category-service.png | Bin 0 -> 2063 bytes .../mozapps/extensions/dictionaryGeneric-16.png | Bin 0 -> 584 bytes .../linux/mozapps/extensions/dictionaryGeneric.png | Bin 0 -> 1290 bytes .../linux/mozapps/extensions/experimentGeneric.png | Bin 0 -> 822 bytes .../mozapps/extensions/extensionGeneric-16.png | Bin 0 -> 713 bytes .../linux/mozapps/extensions/extensionGeneric.png | Bin 0 -> 1862 bytes .../themes/linux/mozapps/extensions/extensions.css | 956 +++ .../linux/mozapps/extensions/localeGeneric.png | Bin 0 -> 1860 bytes .../themes/linux/mozapps/extensions/newaddon.css | 110 + .../linux/mozapps/extensions/selectAddons.css | 162 + .../linux/mozapps/extensions/themeGeneric-16.png | Bin 0 -> 638 bytes .../linux/mozapps/extensions/themeGeneric.png | Bin 0 -> 1734 bytes toolkit/themes/osx/mozapps/extensions/about.css | 78 + .../osx/mozapps/extensions/alerticon-error.png | Bin 0 -> 3402 bytes .../mozapps/extensions/alerticon-info-negative.png | Bin 0 -> 1564 bytes .../mozapps/extensions/alerticon-info-positive.png | Bin 0 -> 1338 bytes .../osx/mozapps/extensions/alerticon-warning.png | Bin 0 -> 1567 bytes .../themes/osx/mozapps/extensions/blocklist.css | 20 + toolkit/themes/osx/mozapps/extensions/cancel.png | Bin 0 -> 115 bytes .../osx/mozapps/extensions/category-available.png | Bin 0 -> 1671 bytes .../mozapps/extensions/category-dictionaries.png | Bin 0 -> 1769 bytes .../osx/mozapps/extensions/category-discover.png | Bin 0 -> 1324 bytes .../mozapps/extensions/category-experiments.png | Bin 0 -> 822 bytes .../osx/mozapps/extensions/category-plugins.png | Bin 0 -> 886 bytes .../osx/mozapps/extensions/category-recent.png | Bin 0 -> 1642 bytes .../osx/mozapps/extensions/category-search.png | Bin 0 -> 2600 bytes .../mozapps/extensions/category-searchengines.png | Bin 0 -> 2814 bytes .../osx/mozapps/extensions/category-service.png | Bin 0 -> 2063 bytes .../mozapps/extensions/dictionaryGeneric-16.png | Bin 0 -> 742 bytes .../osx/mozapps/extensions/dictionaryGeneric.png | Bin 0 -> 1769 bytes .../osx/mozapps/extensions/discover-logo.png | Bin 0 -> 12007 bytes toolkit/themes/osx/mozapps/extensions/eula.css | 47 + .../osx/mozapps/extensions/experimentGeneric.png | Bin 0 -> 822 bytes .../osx/mozapps/extensions/extensionGeneric-16.png | Bin 0 -> 554 bytes .../osx/mozapps/extensions/extensionGeneric.png | Bin 0 -> 1302 bytes .../themes/osx/mozapps/extensions/extensions.css | 1199 +++ toolkit/themes/osx/mozapps/extensions/heart.png | Bin 0 -> 2949 bytes .../osx/mozapps/extensions/localeGeneric.png | Bin 0 -> 2410 bytes .../themes/osx/mozapps/extensions/navigation.png | Bin 0 -> 586 bytes toolkit/themes/osx/mozapps/extensions/newaddon.css | 112 + .../osx/mozapps/extensions/rating-not-won.png | Bin 0 -> 1559 bytes .../themes/osx/mozapps/extensions/rating-won.png | Bin 0 -> 1662 bytes toolkit/themes/osx/mozapps/extensions/search.png | Bin 0 -> 423 bytes .../themes/osx/mozapps/extensions/selectAddons.css | 163 + .../osx/mozapps/extensions/stripes-error.png | Bin 0 -> 1979 bytes .../mozapps/extensions/stripes-info-negative.png | Bin 0 -> 2027 bytes .../mozapps/extensions/stripes-info-positive.png | Bin 0 -> 1852 bytes .../osx/mozapps/extensions/stripes-warning.png | Bin 0 -> 2177 bytes .../osx/mozapps/extensions/themeGeneric-16.png | Bin 0 -> 710 bytes .../themes/osx/mozapps/extensions/themeGeneric.png | Bin 0 -> 2185 bytes .../extensions/toolbarbutton-dropmarker.png | Bin 0 -> 147 bytes toolkit/themes/osx/mozapps/extensions/update.css | 26 + .../osx/mozapps/extensions/xpinstallConfirm.css | 90 + toolkit/themes/shared/extensions/utilities.svg | 25 + .../themes/windows/mozapps/extensions/about.css | 91 + .../windows/mozapps/extensions/alerticon-error.png | Bin 0 -> 3402 bytes .../mozapps/extensions/alerticon-info-negative.png | Bin 0 -> 1564 bytes .../mozapps/extensions/alerticon-info-positive.png | Bin 0 -> 1338 bytes .../mozapps/extensions/alerticon-warning.png | Bin 0 -> 1567 bytes .../windows/mozapps/extensions/blocklist.css | 20 + .../themes/windows/mozapps/extensions/cancel.png | Bin 0 -> 115 bytes .../mozapps/extensions/category-available.png | Bin 0 -> 2235 bytes .../mozapps/extensions/category-dictionaries.png | Bin 0 -> 1665 bytes .../mozapps/extensions/category-discover.png | Bin 0 -> 1355 bytes .../mozapps/extensions/category-experiments.png | Bin 0 -> 822 bytes .../mozapps/extensions/category-plugins.png | Bin 0 -> 1334 bytes .../windows/mozapps/extensions/category-recent.png | Bin 0 -> 2251 bytes .../windows/mozapps/extensions/category-search.png | Bin 0 -> 2600 bytes .../mozapps/extensions/category-searchengines.png | Bin 0 -> 2814 bytes .../mozapps/extensions/category-service.png | Bin 0 -> 2063 bytes .../mozapps/extensions/dictionaryGeneric-16.png | Bin 0 -> 733 bytes .../mozapps/extensions/dictionaryGeneric.png | Bin 0 -> 1665 bytes .../windows/mozapps/extensions/discover-logo.png | Bin 0 -> 12007 bytes toolkit/themes/windows/mozapps/extensions/eula.css | 47 + .../mozapps/extensions/experimentGeneric.png | Bin 0 -> 822 bytes .../mozapps/extensions/extensionGeneric-16.png | Bin 0 -> 716 bytes .../mozapps/extensions/extensionGeneric-48.png | Bin 0 -> 2726 bytes .../mozapps/extensions/extensionGeneric.png | Bin 0 -> 1615 bytes .../windows/mozapps/extensions/extensions.css | 1234 +++ .../themes/windows/mozapps/extensions/heart.png | Bin 0 -> 2949 bytes .../windows/mozapps/extensions/localeGeneric.png | Bin 0 -> 2518 bytes .../windows/mozapps/extensions/navigation.png | Bin 0 -> 1411 bytes .../themes/windows/mozapps/extensions/newaddon.css | 110 + .../windows/mozapps/extensions/rating-not-won.png | Bin 0 -> 1559 bytes .../windows/mozapps/extensions/rating-won.png | Bin 0 -> 1662 bytes .../windows/mozapps/extensions/selectAddons.css | 185 + .../windows/mozapps/extensions/stripes-error.png | Bin 0 -> 1979 bytes .../mozapps/extensions/stripes-info-negative.png | Bin 0 -> 2027 bytes .../mozapps/extensions/stripes-info-positive.png | Bin 0 -> 1852 bytes .../windows/mozapps/extensions/stripes-warning.png | Bin 0 -> 2177 bytes .../windows/mozapps/extensions/themeGeneric-16.png | Bin 0 -> 837 bytes .../windows/mozapps/extensions/themeGeneric.png | Bin 0 -> 2094 bytes .../themes/windows/mozapps/extensions/update.css | 26 + .../mozapps/extensions/xpinstallConfirm.css | 101 + 875 files changed, 111377 insertions(+) create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/about.dtd create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/blocklist.dtd create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.dtd create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.properties create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.dtd create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.properties create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/update.dtd create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/update.properties create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.dtd create mode 100644 toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.properties create mode 100644 toolkit/mozapps/extensions/AddonManager.jsm create mode 100644 toolkit/mozapps/extensions/AddonPathService.cpp create mode 100644 toolkit/mozapps/extensions/AddonPathService.h create mode 100644 toolkit/mozapps/extensions/ChromeManifestParser.jsm create mode 100644 toolkit/mozapps/extensions/DeferredSave.jsm create mode 100644 toolkit/mozapps/extensions/LightweightThemeManager.jsm create mode 100644 toolkit/mozapps/extensions/addonManager.js create mode 100644 toolkit/mozapps/extensions/amContentHandler.js create mode 100644 toolkit/mozapps/extensions/amIAddonManager.idl create mode 100644 toolkit/mozapps/extensions/amIAddonPathService.idl create mode 100644 toolkit/mozapps/extensions/amIWebInstallListener.idl create mode 100644 toolkit/mozapps/extensions/amIWebInstaller.idl create mode 100644 toolkit/mozapps/extensions/amInstallTrigger.js create mode 100644 toolkit/mozapps/extensions/amWebInstallListener.js create mode 100644 toolkit/mozapps/extensions/content/OpenH264-license.txt create mode 100644 toolkit/mozapps/extensions/content/about.js create mode 100644 toolkit/mozapps/extensions/content/about.xul create mode 100644 toolkit/mozapps/extensions/content/blocklist.css create mode 100644 toolkit/mozapps/extensions/content/blocklist.js create mode 100644 toolkit/mozapps/extensions/content/blocklist.xml create mode 100644 toolkit/mozapps/extensions/content/blocklist.xul create mode 100644 toolkit/mozapps/extensions/content/eula.js create mode 100644 toolkit/mozapps/extensions/content/eula.xul create mode 100644 toolkit/mozapps/extensions/content/extensions.css create mode 100644 toolkit/mozapps/extensions/content/extensions.js create mode 100644 toolkit/mozapps/extensions/content/extensions.xml create mode 100644 toolkit/mozapps/extensions/content/extensions.xul create mode 100644 toolkit/mozapps/extensions/content/gmpPrefs.xul create mode 100644 toolkit/mozapps/extensions/content/list.js create mode 100644 toolkit/mozapps/extensions/content/list.xul create mode 100644 toolkit/mozapps/extensions/content/newaddon.js create mode 100644 toolkit/mozapps/extensions/content/newaddon.xul create mode 100644 toolkit/mozapps/extensions/content/pluginPrefs.xul create mode 100644 toolkit/mozapps/extensions/content/selectAddons.css create mode 100644 toolkit/mozapps/extensions/content/selectAddons.js create mode 100644 toolkit/mozapps/extensions/content/selectAddons.xml create mode 100644 toolkit/mozapps/extensions/content/selectAddons.xul create mode 100644 toolkit/mozapps/extensions/content/setting.xml create mode 100644 toolkit/mozapps/extensions/content/update.js create mode 100644 toolkit/mozapps/extensions/content/update.xul create mode 100644 toolkit/mozapps/extensions/content/updateinfo.xsl create mode 100644 toolkit/mozapps/extensions/content/xpinstallConfirm.css create mode 100644 toolkit/mozapps/extensions/content/xpinstallConfirm.js create mode 100644 toolkit/mozapps/extensions/content/xpinstallConfirm.xul create mode 100644 toolkit/mozapps/extensions/content/xpinstallItem.xml create mode 100644 toolkit/mozapps/extensions/extensions.manifest create mode 100644 toolkit/mozapps/extensions/internal/AddonLogging.jsm create mode 100644 toolkit/mozapps/extensions/internal/AddonRepository.jsm create mode 100644 toolkit/mozapps/extensions/internal/AddonRepository_SQLiteMigrator.jsm create mode 100644 toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm create mode 100644 toolkit/mozapps/extensions/internal/Content.js create mode 100644 toolkit/mozapps/extensions/internal/GMPProvider.jsm create mode 100644 toolkit/mozapps/extensions/internal/LightweightThemeImageOptimizer.jsm create mode 100644 toolkit/mozapps/extensions/internal/PluginProvider.jsm create mode 100644 toolkit/mozapps/extensions/internal/SpellCheckDictionaryBootstrap.js create mode 100644 toolkit/mozapps/extensions/internal/XPIProvider.jsm create mode 100644 toolkit/mozapps/extensions/internal/XPIProviderUtils.js create mode 100644 toolkit/mozapps/extensions/internal/moz.build create mode 100644 toolkit/mozapps/extensions/jar.mn create mode 100644 toolkit/mozapps/extensions/moz.build create mode 100644 toolkit/mozapps/extensions/nsBlocklistService.js create mode 100644 toolkit/mozapps/extensions/test/AddonManagerTesting.jsm create mode 100644 toolkit/mozapps/extensions/test/Makefile.in create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_hard1_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_hard1_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_hard1_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_regexp1_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_regexp1_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_regexp1_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft1_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft1_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft1_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft2_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft2_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft2_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft3_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft3_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft3_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft4_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft4_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft4_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft5_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft5_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/blocklist_soft5_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/bootstrap_globals/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/bootstrap_globals/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/min1max1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/min1max2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/min1max3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/min1max3b/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/override1x2-1x3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_3/icon.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_AddonRepository_3/preview.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_1/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_1/version.jsm create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_2/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_2/version.jsm create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_3/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_3/version.jsm create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap1_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap2_1/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bootstrap2_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_a_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_a_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_b_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_b_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_c_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_c_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_d_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_d_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_e_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_e_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_f_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_f_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_g_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug299716_g_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_7/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_8/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug324121_9/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug335238_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug371495/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug394300_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug394300_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug397778/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug425657/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug470377_5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug521905/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug567173/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug567184/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug567184/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_1/testfile create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_1/testfile1 create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_2/testfile create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug587088_2/testfile2 create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug594058/directory/file1 create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug594058/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug595573/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug655254/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug655254_2/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug655254_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug659772/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/test.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_1/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_2/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug740612_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug757663/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_cacheflush1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_cacheflush2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/inner.jar create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/components.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/components/other/something.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_6/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_chromemanifest_6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_data_directory/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_db_sanity_1_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_db_sanity_1_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary/dictionaries/ab-CD.dic create mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_2/dictionaries/ab-CD.dic create mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_dictionary_5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_distribution1_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_experiment1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_filepointer/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_getresource/icon.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_getresource/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_getresource/subdir/subfile.txt create mode 100644 toolkit/mozapps/extensions/test/addons/test_install1/icon.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_install1/icon64.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_install1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_install2_1/icon.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_install2_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_install2_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_install3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon4.xpi create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon5.jar create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon6.xpi create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/addon7.jar create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/badaddon.jar create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/badaddon.xpi create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/icon.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_install4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_install5/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_install5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_install6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_jetpack/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_jetpack/harness-options.json create mode 100644 toolkit/mozapps/extensions/test/addons/test_jetpack/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_langpack/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_langpack/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_locale/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_locked2_5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_locked2_6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate4_7/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate7/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate8/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate8/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate9/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_theme/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_theme/preview.png create mode 100644 toolkit/mozapps/extensions/test/addons/test_undoincompatible/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_undoincompatible/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_undouninstall1/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_undouninstall1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_update/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_update12/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_update8/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid2_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid2_5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid3_3/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid3_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid4_4/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/addons/test_updateid4_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/upgradeable1x2-3_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/upgradeable1x2-3_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/Makefile.in create mode 100644 toolkit/mozapps/extensions/test/browser/addon_about.xul create mode 100644 toolkit/mozapps/extensions/test/browser/addon_prefs.xul create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_10/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_3/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_4/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_5/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_7/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_8_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug557956_9_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug567127_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug567127_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_bug596336_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_dragdrop2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_experiment1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1/options.xul create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/binding.xml create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/options.xul create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_custom/string.dtd create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_info/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_info/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_inlinesettings1_info/options.xul create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_install1_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_install1_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_installssl/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_searching/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_searching/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/addons/browser_select_compatoverrides_1/install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/blockNoPlugins.xml create mode 100644 toolkit/mozapps/extensions/test/browser/blockPluginHard.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser-common.ini create mode 100644 toolkit/mozapps/extensions/test/browser/browser-window.ini create mode 100644 toolkit/mozapps/extensions/test/browser/browser.ini create mode 100644 toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_about.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_addonrepository_performance.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug523784.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557943.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956_8_2.xpi create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug557956_9_2.xpi create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562797.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562854.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562890.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562899.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug562992.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug567127.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug567137.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug570760.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug572561.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug573062.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug577990.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug580298.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug581076.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug586574.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug587970.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug590347.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug591465.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug591465.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug591663.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug593535.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug593535.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug596336.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug608316.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug610764.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug616841.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug618502.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug679604.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_bug714593.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_checkAddonCompatibility.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_debug_button.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_details.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_discovery.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_discovery_install.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_dragdrop.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_eula.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_eula.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_experiments.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_globalinformations.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_globalwarnings.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_inlinesettings.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_inlinesettings_custom.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_inlinesettings_info.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.rdf^headers^ create mode 100644 toolkit/mozapps/extensions/test/browser/browser_install.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_install1_3.xpi create mode 100644 toolkit/mozapps/extensions/test/browser/browser_installssl.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_list.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_manualupdates.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_metadataTimeout.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_newaddon.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_openDialog.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_plugin_enabled_state_locked.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_pluginprefs.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_purchase.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_purchase.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_recentupdates.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_searching.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_searching.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_searching_empty.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_select_compatoverrides.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_select_compatoverrides.xml create mode 100644 toolkit/mozapps/extensions/test/browser/browser_select_confirm.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_select_selection.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_select_update.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_sorting.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_sorting_plugins.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_tabsettings.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_task_next_test.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_types.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_uninstalling.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_updateid.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_updatessl.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_updatessl.rdf create mode 100644 toolkit/mozapps/extensions/test/browser/browser_updatessl.rdf^headers^ create mode 100644 toolkit/mozapps/extensions/test/browser/cancelCompatCheck.sjs create mode 100644 toolkit/mozapps/extensions/test/browser/discovery.html create mode 100644 toolkit/mozapps/extensions/test/browser/discovery_frame.html create mode 100644 toolkit/mozapps/extensions/test/browser/discovery_install.html create mode 100644 toolkit/mozapps/extensions/test/browser/head.js create mode 100644 toolkit/mozapps/extensions/test/browser/more_options.xul create mode 100644 toolkit/mozapps/extensions/test/browser/moz.build create mode 100644 toolkit/mozapps/extensions/test/browser/options.xul create mode 100644 toolkit/mozapps/extensions/test/browser/plugin_test.html create mode 100644 toolkit/mozapps/extensions/test/browser/redirect.sjs create mode 100644 toolkit/mozapps/extensions/test/browser/releaseNotes.xhtml create mode 100644 toolkit/mozapps/extensions/test/mochitest/file_bug687194.xpi create mode 100644 toolkit/mozapps/extensions/test/mochitest/file_empty.html create mode 100644 toolkit/mozapps/extensions/test/mochitest/mochitest.ini create mode 100644 toolkit/mozapps/extensions/test/mochitest/test_bug609794.html create mode 100644 toolkit/mozapps/extensions/test/mochitest/test_bug687194.html create mode 100644 toolkit/mozapps/extensions/test/mochitest/test_bug887098.html create mode 100644 toolkit/mozapps/extensions/test/moz.build create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update1.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_block.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_empty.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_start.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/bug455906_warn.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/corrupt.xpi create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/corruptfile.xpi create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/empty.xpi create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/pluginInfoURL_block.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_cache.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_compatmode_ignore.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_compatmode_normal.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_compatmode_strict.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_empty.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_failed.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_AddonRepository_getAddonsByIDs.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_backgroundupdate.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_metadata_filters_1.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_prefs_1.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_blocklist_regexp_1.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug299716.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug299716_2.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug324121.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug393285.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug394300.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug424262.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug449027_app.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug449027_toolkit.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug468528.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_1.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_2.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_3.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_4.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/install_5.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_1.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_2.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_3.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_4.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug470377/update_5.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_1.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_2.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_3_empty.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_3_outdated_1.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug514327_3_outdated_2.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug526598_1.xpi create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug526598_2.xpi create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug541420.xpi create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug542391.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug554133.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug619730.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_bug655254.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_compatoverrides.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_corrupt.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_dictionary.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/install.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/subdir/dummy.txt create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_distribution2_2/subdir/subdir2/dummy2.txt create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist2.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_OSVersion.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_install.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_install.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_migrate.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_overrideblocklist/ancient.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_overrideblocklist/new.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_overrideblocklist/old.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_pluginBlocklistCtp.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_pluginBlocklistCtpUndo.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_sourceURI.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_update.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_update.xml create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecheck.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecompatmode_ignore.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecompatmode_normal.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updatecompatmode_strict.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_updateid.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/unsigned.xpi create mode 100644 toolkit/mozapps/extensions/test/xpcshell/head_addons.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/head_unpack.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_cache.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_AddonRepository_compatmode.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_ChromeManifestParser.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_DeferredSave.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_LightweightThemeManager.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_XPIStates.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_XPIcancel.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_addon_path_service.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_asyncBlocklistLoad.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bad_json.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_badschema.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_globals.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bootstrap_resource.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug299716.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug299716_2.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug324121.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug371495.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug384052.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug394300.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug397778.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug424262.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug425657.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug430120.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug449027.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug465190.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug468528.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_1.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_1_strictcompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_2.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_3.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_3_strictcompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug470377_4.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug514327_1.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug514327_2.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug514327_3.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug521905.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug526598.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug541420.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug542391.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug554133.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug559800.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug563256.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug564030.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug566626.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug567184.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug569138.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug570173.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug576735.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug587088.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug594058.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug595081.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug595573.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug596343.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug596607.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug616841.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug619730.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug620837.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug655254.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug659772.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug740612.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug753900.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug757663.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug953156.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_checkCompatibility_themeOverride.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_checkcompatibility.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_childprocess.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_compatoverrides.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_corrupt.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_corrupt_strictcompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_corruptfile.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_dataDirectory.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_default_providers_pref.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_dictionary.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_disable.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_distribution.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_dss.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_duplicateplugins.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_error.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_experiment.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_filepointer.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_fuel.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_general.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_getresource.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Device.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_DriverNew.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverNew.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_DriverOld.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Equal_OK.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_DriverOld.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_GTE_OK.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_No_Comparison.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OK.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OS.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_match.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_DriverVersion.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_OSVersion_mismatch_OSVersion.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Vendor.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_prefs.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_gmpProvider.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_hasbinarycomponents.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_install.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_install_icons.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_install_strictcompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_isDebuggable.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_isReady.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_langpack.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_locale.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_locked.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_locked2.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_locked_strictcompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_manifest.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_mapURIToAddonID.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_metadata_update.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate5.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrateAddonRepository.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate_max_version.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_multiprocessCompatible.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_no_addons.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_onPropertyChanged_appDisabled.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_overrideblocklist.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_permissions.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_permissions_prefs.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pluginBlocklistCtp.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pluginInfoURL.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pluginchange.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_plugins.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_pref_properties.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_markSafe.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_shutdown.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_unsafe_access_shutdown.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_provider_unsafe_access_startup.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_registry.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_safemode.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_shutdown.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_sourceURI.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_startup.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_strictcompatibility.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_syncGUID.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_targetPlatforms.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_theme.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_types.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_undothemeuninstall.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_undouninstall.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_uninstall.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_updateCancel.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update_compatmode.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update_ignorecompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_update_strictcompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_updatecheck.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_updateid.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_upgrade.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_upgrade_strictcompat.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini create mode 100644 toolkit/mozapps/extensions/test/xpcshell/xpcshell-unpack.ini create mode 100644 toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini create mode 100644 toolkit/mozapps/extensions/test/xpinstall/authRedirect.sjs create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser.ini create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badargs.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badargs2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badhash.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_badhashtype.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug540558.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug611242.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug638292.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cancel.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_concurrent_installs.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies3.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_cookies4.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_corrupt.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_datauri.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_empty.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_enabled2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_enabled3.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_hash.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_hash2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash3.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash4.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash5.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_httphash6.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_installchrome.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile3.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_localfile4.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_multipackage.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway3.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_navigateaway4.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_offline.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_relative.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_multiple.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_naming.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_tampered.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_trigger.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_untrusted.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_signed_url.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_softwareupdate.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_switchtab.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_trigger_redirect.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_iframe.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_xorigin.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_url.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist2.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist3.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist4.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist5.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist6.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/browser_whitelist7.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/bug540558.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/bug638292.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/bug645699.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/concurrent_installs.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs create mode 100644 toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/empty.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/enabled.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs create mode 100644 toolkit/mozapps/extensions/test/xpinstall/head.js create mode 100644 toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/installchrome.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/installtrigger.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/navigate.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/redirect.sjs create mode 100644 toolkit/mozapps/extensions/test/xpinstall/restartless.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/signed2.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs create mode 100644 toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/theme.xpi create mode 100644 toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html create mode 100644 toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi create mode 100644 toolkit/themes/linux/mozapps/extensions/category-available.png create mode 100644 toolkit/themes/linux/mozapps/extensions/category-dictionaries.png create mode 100644 toolkit/themes/linux/mozapps/extensions/category-discover.png create mode 100644 toolkit/themes/linux/mozapps/extensions/category-experiments.png create mode 100644 toolkit/themes/linux/mozapps/extensions/category-plugins.png create mode 100644 toolkit/themes/linux/mozapps/extensions/category-recent.png create mode 100644 toolkit/themes/linux/mozapps/extensions/category-search.png create mode 100644 toolkit/themes/linux/mozapps/extensions/category-service.png create mode 100644 toolkit/themes/linux/mozapps/extensions/dictionaryGeneric-16.png create mode 100644 toolkit/themes/linux/mozapps/extensions/dictionaryGeneric.png create mode 100644 toolkit/themes/linux/mozapps/extensions/experimentGeneric.png create mode 100644 toolkit/themes/linux/mozapps/extensions/extensionGeneric-16.png create mode 100644 toolkit/themes/linux/mozapps/extensions/extensionGeneric.png create mode 100644 toolkit/themes/linux/mozapps/extensions/extensions.css create mode 100644 toolkit/themes/linux/mozapps/extensions/localeGeneric.png create mode 100644 toolkit/themes/linux/mozapps/extensions/newaddon.css create mode 100644 toolkit/themes/linux/mozapps/extensions/selectAddons.css create mode 100644 toolkit/themes/linux/mozapps/extensions/themeGeneric-16.png create mode 100644 toolkit/themes/linux/mozapps/extensions/themeGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/about.css create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-error.png create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png create mode 100644 toolkit/themes/osx/mozapps/extensions/alerticon-warning.png create mode 100644 toolkit/themes/osx/mozapps/extensions/blocklist.css create mode 100644 toolkit/themes/osx/mozapps/extensions/cancel.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-available.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-dictionaries.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-discover.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-experiments.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-plugins.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-recent.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-search.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-searchengines.png create mode 100644 toolkit/themes/osx/mozapps/extensions/category-service.png create mode 100644 toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png create mode 100644 toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/discover-logo.png create mode 100644 toolkit/themes/osx/mozapps/extensions/eula.css create mode 100644 toolkit/themes/osx/mozapps/extensions/experimentGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png create mode 100644 toolkit/themes/osx/mozapps/extensions/extensionGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/extensions.css create mode 100644 toolkit/themes/osx/mozapps/extensions/heart.png create mode 100644 toolkit/themes/osx/mozapps/extensions/localeGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/navigation.png create mode 100644 toolkit/themes/osx/mozapps/extensions/newaddon.css create mode 100644 toolkit/themes/osx/mozapps/extensions/rating-not-won.png create mode 100644 toolkit/themes/osx/mozapps/extensions/rating-won.png create mode 100644 toolkit/themes/osx/mozapps/extensions/search.png create mode 100644 toolkit/themes/osx/mozapps/extensions/selectAddons.css create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-error.png create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png create mode 100644 toolkit/themes/osx/mozapps/extensions/stripes-warning.png create mode 100644 toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png create mode 100644 toolkit/themes/osx/mozapps/extensions/themeGeneric.png create mode 100644 toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png create mode 100644 toolkit/themes/osx/mozapps/extensions/update.css create mode 100644 toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css create mode 100644 toolkit/themes/shared/extensions/utilities.svg create mode 100644 toolkit/themes/windows/mozapps/extensions/about.css create mode 100644 toolkit/themes/windows/mozapps/extensions/alerticon-error.png create mode 100644 toolkit/themes/windows/mozapps/extensions/alerticon-info-negative.png create mode 100644 toolkit/themes/windows/mozapps/extensions/alerticon-info-positive.png create mode 100644 toolkit/themes/windows/mozapps/extensions/alerticon-warning.png create mode 100644 toolkit/themes/windows/mozapps/extensions/blocklist.css create mode 100644 toolkit/themes/windows/mozapps/extensions/cancel.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-available.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-dictionaries.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-discover.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-experiments.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-plugins.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-recent.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-search.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-searchengines.png create mode 100644 toolkit/themes/windows/mozapps/extensions/category-service.png create mode 100644 toolkit/themes/windows/mozapps/extensions/dictionaryGeneric-16.png create mode 100644 toolkit/themes/windows/mozapps/extensions/dictionaryGeneric.png create mode 100644 toolkit/themes/windows/mozapps/extensions/discover-logo.png create mode 100644 toolkit/themes/windows/mozapps/extensions/eula.css create mode 100644 toolkit/themes/windows/mozapps/extensions/experimentGeneric.png create mode 100644 toolkit/themes/windows/mozapps/extensions/extensionGeneric-16.png create mode 100644 toolkit/themes/windows/mozapps/extensions/extensionGeneric-48.png create mode 100644 toolkit/themes/windows/mozapps/extensions/extensionGeneric.png create mode 100644 toolkit/themes/windows/mozapps/extensions/extensions.css create mode 100644 toolkit/themes/windows/mozapps/extensions/heart.png create mode 100644 toolkit/themes/windows/mozapps/extensions/localeGeneric.png create mode 100644 toolkit/themes/windows/mozapps/extensions/navigation.png create mode 100644 toolkit/themes/windows/mozapps/extensions/newaddon.css create mode 100644 toolkit/themes/windows/mozapps/extensions/rating-not-won.png create mode 100644 toolkit/themes/windows/mozapps/extensions/rating-won.png create mode 100644 toolkit/themes/windows/mozapps/extensions/selectAddons.css create mode 100644 toolkit/themes/windows/mozapps/extensions/stripes-error.png create mode 100644 toolkit/themes/windows/mozapps/extensions/stripes-info-negative.png create mode 100644 toolkit/themes/windows/mozapps/extensions/stripes-info-positive.png create mode 100644 toolkit/themes/windows/mozapps/extensions/stripes-warning.png create mode 100644 toolkit/themes/windows/mozapps/extensions/themeGeneric-16.png create mode 100644 toolkit/themes/windows/mozapps/extensions/themeGeneric.png create mode 100644 toolkit/themes/windows/mozapps/extensions/update.css create mode 100644 toolkit/themes/windows/mozapps/extensions/xpinstallConfirm.css diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/about.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/about.dtd new file mode 100644 index 000000000..4f9098966 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/about.dtd @@ -0,0 +1,9 @@ + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/blocklist.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/blocklist.dtd new file mode 100644 index 000000000..f393cc906 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/blocklist.dtd @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd new file mode 100644 index 000000000..c74fdeb2f --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties new file mode 100644 index 000000000..c4e2660ee --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties @@ -0,0 +1,177 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#LOCALIZATION NOTE (aboutWindowTitle) %S is the addon name +aboutWindowTitle=About %S +aboutWindowCloseButton=Close +#LOCALIZATION NOTE (aboutWindowVersionString) %S is the addon version +aboutWindowVersionString=version %S +#LOCALIZATION NOTE (aboutAddon) %S is the addon name +aboutAddon=About %S + +#LOCALIZATION NOTE (uninstallNotice) %S is the add-on name +uninstallNotice=%S has been removed. + +#LOCALIZATION NOTE (numReviews): Semicolon-separated list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 is the number of reviews +numReviews=#1 review;#1 reviews + +#LOCALIZATION NOTE (dateUpdated) %S is the date the addon was last updated +dateUpdated=Updated %S + +#LOCALIZATION NOTE (notification.incompatible) %1$S is the add-on name, %2$S is brand name, %3$S is application version +notification.incompatible=%1$S is incompatible with %2$S %3$S. +notification.jetsdk=This is a Jetpack/SDK extension which are not supported in %1$S %2$S. +#LOCALIZATION NOTE (notification.blocked) %1$S is the add-on name +notification.blocked=%1$S has been disabled due to security or stability issues. +notification.blocked.link=More Information +#LOCALIZATION NOTE (notification.softblocked) %1$S is the add-on name +notification.softblocked=%1$S is known to cause security or stability issues. +notification.softblocked.link=More Information +#LOCALIZATION NOTE (notification.outdated) %1$S is the add-on name +notification.outdated=An important update is available for %1$S. +notification.outdated.link=Update Now +#LOCALIZATION NOTE (notification.vulnerableUpdatable) %1$S is the add-on name +notification.vulnerableUpdatable=%1$S is known to be vulnerable and should be updated. +notification.vulnerableUpdatable.link=Update Now +#LOCALIZATION NOTE (notification.vulnerableNoUpdate) %1$S is the add-on name +notification.vulnerableNoUpdate=%1$S is known to be vulnerable. Use with caution. +notification.vulnerableNoUpdate.link=More Information +#LOCALIZATION NOTE (notification.enable) %1$S is the add-on name, %2$S is brand name +notification.enable=%1$S will be enabled after you restart %2$S. +#LOCALIZATION NOTE (notification.disable) %1$S is the add-on name, %2$S is brand name +notification.disable=%1$S will be disabled after you restart %2$S. +#LOCALIZATION NOTE (notification.install) %1$S is the add-on name, %2$S is brand name +notification.install=%1$S will be installed after you restart %2$S. +#LOCALIZATION NOTE (notification.uninstall) %1$S is the add-on name, %2$S is brand name +notification.uninstall=%1$S will be uninstalled after you restart %2$S. +#LOCALIZATION NOTE (notification.upgrade) %1$S is the add-on name, %2$S is brand name +notification.upgrade=%1$S will be updated after you restart %2$S. +#LOCALIZATION NOTE (notification.downloadError) %1$S is the add-on name. +notification.downloadError=There was an error downloading %1$S. +notification.downloadError.retry=Try again +notification.downloadError.retry.tooltip=Try downloading this add-on again +#LOCALIZATION NOTE (notification.installError) %1$S is the add-on name. +notification.installError=There was an error installing %1$S. +notification.installError.retry=Try again +notification.installError.retry.tooltip=Try downloading and installing this add-on again +#LOCALIZATION NOTE (notification.gmpPending) %1$S is the add-on name. +notification.gmpPending=%1$S will be installed shortly. + +#LOCALIZATION NOTE (contributionAmount2) %S is the currency amount recommended for contributions +contributionAmount2=Suggested Contribution: %S + +installDownloading=Downloading +installDownloaded=Downloaded +installDownloadFailed=Error downloading +installVerifying=Verifying +installInstalling=Installing +installEnablePending=Restart to enable +installDisablePending=Restart to disable +installFailed=Error installing +installCancelled=Install cancelled + +#LOCALIZATION NOTE (details.notification.incompatible) %1$S is the add-on name, %2$S is brand name, %3$S is application version +details.notification.incompatible=%1$S is incompatible with %2$S %3$S. +#LOCALIZATION NOTE (details.notification.blocked) %1$S is the add-on name +details.notification.blocked=%1$S has been disabled due to security or stability issues. +details.notification.blocked.link=More Information +#LOCALIZATION NOTE (details.notification.softblocked) %1$S is the add-on name +details.notification.softblocked=%1$S is known to cause security or stability issues. +details.notification.softblocked.link=More Information +#LOCALIZATION NOTE (details.notification.outdated) %1$S is the add-on name +details.notification.outdated=An important update is available for %1$S. +details.notification.outdated.link=Update Now +#LOCALIZATION NOTE (details.notification.vulnerableUpdatable) %1$S is the add-on name +details.notification.vulnerableUpdatable=%1$S is known to be vulnerable and should be updated. +details.notification.vulnerableUpdatable.link=Update Now +#LOCALIZATION NOTE (details.notification.vulnerableNoUpdate) %1$S is the add-on name +details.notification.vulnerableNoUpdate=%1$S is known to be vulnerable. Use with caution. +details.notification.vulnerableNoUpdate.link=More Information +#LOCALIZATION NOTE (details.notification.enable) %1$S is the add-on name, %2$S is brand name +details.notification.enable=%1$S will be enabled after you restart %2$S. +#LOCALIZATION NOTE (details.notification.disable) %1$S is the add-on name, %2$S is brand name +details.notification.disable=%1$S will be disabled after you restart %2$S. +#LOCALIZATION NOTE (details.notification.install) %1$S is the add-on name, %2$S is brand name +details.notification.install=%1$S will be installed after you restart %2$S. +#LOCALIZATION NOTE (details.notification.uninstall) %1$S is the add-on name, %2$S is brand name +details.notification.uninstall=%1$S will be uninstalled after you restart %2$S. +#LOCALIZATION NOTE (details.notification.upgrade) %1$S is the add-on name, %2$S is brand name +details.notification.upgrade=%1$S will be updated after you restart %2$S. +#LOCALIZATION NOTE (details.notification.gmpPending) %1$S is the add-on name +details.notification.gmpPending=%1$S will be installed shortly. + +# LOCALIZATION NOTE (details.experiment.time.daysRemaining): +# Semicolon-separated list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 is the number of days from now that the experiment will remain active (detail view). +details.experiment.time.daysRemaining=#1 day remaining;#1 days remaining +#LOCALIZATION NOTE (details.experiment.time.endsToday) The experiment will end in less than a day (detail view). +details.experiment.time.endsToday=Less than a day remaining +# LOCALIZATION NOTE (details.experiment.time.daysPassed): +# Semicolon-separated list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 is the number of days since the experiment ran (detail view). +details.experiment.time.daysPassed=#1 day ago;#1 days ago +#LOCALIZATION NOTE (details.experiment.time.endedToday) The experiment ended less than a day ago (detail view). +details.experiment.time.endedToday=Less than a day ago +#LOCALIZATION NOTE (details.experiment.state.active) This experiment is active (detail view). +details.experiment.state.active=Active +#LOCALIZATION NOTE (details.experiment.state.complete) This experiment is complete (it was previously active) (detail view). +details.experiment.state.complete=Complete + +# LOCALIZATION NOTE (experiment.time.daysRemaining): +# Semicolon-separated list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 is the number of days from now that the experiment will remain active (list view item). +experiment.time.daysRemaining=#1 day remaining;#1 days remaining +#LOCALIZATION NOTE (experiment.time.endsToday) The experiment will end in less than a day (list view item). +experiment.time.endsToday=Less than a day remaining +# LOCALIZATION NOTE (experiment.time.daysPassed): +# Semicolon-separated list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 is the number of days since the experiment ran (list view item). +experiment.time.daysPassed=#1 day ago;#1 days ago +#LOCALIZATION NOTE (experiment.time.endedToday) The experiment ended less than a day ago (list view item). +experiment.time.endedToday=Less than a day ago +#LOCALIZATION NOTE (experiment.state.active) This experiment is active (list view item). +experiment.state.active=Active +#LOCALIZATION NOTE (experiment.state.complete) This experiment is complete (it was previously active) (list view item). +experiment.state.complete=Complete + +installFromFile.dialogTitle=Select add-on to install +installFromFile.filterName=Add-ons + +uninstallAddonTooltip=Uninstall this add-on +uninstallAddonRestartRequiredTooltip=Uninstall this add-on (restart required) +enableAddonTooltip=Enable this add-on +enableAddonRestartRequiredTooltip=Enable this add-on (restart required) +disableAddonTooltip=Disable this add-on +disableAddonRestartRequiredTooltip=Disable this add-on (restart required) + +#LOCALIZATION NOTE (showAllSearchResults): Semicolon-separated list of plural forms. +# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals +# #1 is the total number of search results +showAllSearchResults=See one result;See all #1 results + +#LOCALIZATION NOTE (addon.purchase.label) displayed on a button in the list +# view, %S is the price of the add-on including currency symbol +addon.purchase.label=Purchase for %S… +addon.purchase.tooltip=Visit the add-ons gallery to purchase this add-on +#LOCALIZATION NOTE (cmd.purchaseAddon.label) displayed on a button in the detail +# view, %S is the price of the add-on including currency symbol +cmd.purchaseAddon.label=Purchase for %S… +cmd.purchaseAddon.accesskey=u + +#LOCALIZATION NOTE (eulaHeader) %S is name of the add-on asking the user to agree to the EULA +eulaHeader=%S requires that you accept the following End User License Agreement before installation can proceed: + +type.extension.name=Extensions +type.theme.name=Appearance +type.locale.name=Languages +type.plugin.name=Plugins +type.dictionary.name=Dictionaries +type.service.name=Services +type.experiment.name=Experiments diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.dtd new file mode 100644 index 000000000..1307cebb9 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.dtd @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.properties b/toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.properties new file mode 100644 index 000000000..bd5997a26 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/newaddon.properties @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#LOCALIZATION NOTE (name) %1$S is the add-on name, %2$S is the add-on version +name=%1$S %2$S +#LOCALIZATION NOTE (author) %S is the author of the add-on +author=By %S +#LOCALIZATION NOTE (location) %S is the path the add-on is installed in +location=Location: %S diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.dtd new file mode 100644 index 000000000..2f6f1cd57 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.dtd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.properties b/toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.properties new file mode 100644 index 000000000..2824758d6 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/selectAddons.properties @@ -0,0 +1,21 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#LOCALIZATION NOTE (source.profile) add-ons installed by the user, this may be +# translated as "You" or "User" depending on the locale +source.profile=You +#LOCALIZATION NOTE (source.bundled) add-ons shipped with the application, and thus +# treated as installed by the user. This may be +# translated as "You" or "User" depending on the locale +source.bundled=You (Bundled) +#LOCALIZATION NOTE (source.other) add-ons installed by other applications +# installed on the computer +source.other=Third Party + +action.enabled=Will be enabled +action.disabled=Will be disabled +action.autoupdate=Will be updated to be compatible +action.incompatible=Will be enabled when compatible +action.neededupdate=Update to make compatible +action.unneededupdate=Optional update diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/update.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/update.dtd new file mode 100644 index 000000000..6c820e088 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/update.dtd @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/update.properties b/toolkit/locales/en-US/chrome/mozapps/extensions/update.properties new file mode 100644 index 000000000..7cf79f9c1 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/update.properties @@ -0,0 +1,21 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +mismatchCheckNow=Check Now +mismatchCheckNowAccesskey=C +mismatchDontCheck=Don't Check +mismatchDontCheckAccesskey=D +installButtonText=Install Now +installButtonTextAccesskey=I +nextButtonText=Next > +nextButtonTextAccesskey=N +cancelButtonText=Cancel +cancelButtonTextAccesskey=C +statusPrefix=Finished checking %S +downloadingPrefix=Downloading: %S +installingPrefix=Installing: %S +closeButton=Close +installErrors=%S was unable to install updates for the following add-ons: +checkingErrors=%S was unable to check for updates for the following add-ons: +installErrorItemFormat=%S (%S) diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.dtd new file mode 100644 index 000000000..6a7d17a16 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.dtd @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.properties b/toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.properties new file mode 100644 index 000000000..b538e9e90 --- /dev/null +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/xpinstallConfirm.properties @@ -0,0 +1,16 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +unverified=(Author not verified) +signed=(%S) + +itemWarnIntroMultiple=You have asked to install the following %S items: +itemWarnIntroSingle=You have asked to install the following item: +installButtonDisabledLabel=Install (%S) +installButtonLabel=Install Now + +installComplete=Software Installation is complete. You will have to restart %S for changes to take effect. +installCompleteTitle=Installation Complete + +error-203=Error Installing Item diff --git a/toolkit/mozapps/extensions/AddonManager.jsm b/toolkit/mozapps/extensions/AddonManager.jsm new file mode 100644 index 000000000..38303726b --- /dev/null +++ b/toolkit/mozapps/extensions/AddonManager.jsm @@ -0,0 +1,3027 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +// Cannot use Services.appinfo here, or else xpcshell-tests will blow up, as +// most tests later register different nsIAppInfo implementations, which +// wouldn't be reflected in Services.appinfo anymore, as the lazy getter +// underlying it would have been initialized if we used it here. +if ("@mozilla.org/xre/app-info;1" in Cc) { + let runtime = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime); + if (runtime.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + // Refuse to run in child processes. + throw new Error("You cannot use the AddonManager in child processes!"); + } +} + + +const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion"; +const PREF_DEFAULT_PROVIDERS_ENABLED = "extensions.defaultProviders.enabled"; +const PREF_EM_UPDATE_ENABLED = "extensions.update.enabled"; +const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion"; +const PREF_EM_LAST_PLATFORM_VERSION = "extensions.lastPlatformVersion"; +const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"; +const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility"; +const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; +const PREF_EM_UPDATE_BACKGROUND_URL = "extensions.update.background.url"; +const PREF_APP_UPDATE_ENABLED = "app.update.enabled"; +const PREF_APP_UPDATE_AUTO = "app.update.auto"; +const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; +const PREF_SELECTED_LOCALE = "general.useragent.locale"; +const UNKNOWN_XPCOM_ABI = "unknownABI"; + +const UPDATE_REQUEST_VERSION = 2; +const CATEGORY_UPDATE_PARAMS = "extension-update-params"; + +const XMLURI_BLOCKLIST = "http://www.mozilla.org/2006/addons-blocklist"; + +const KEY_PROFILEDIR = "ProfD"; +const KEY_APPDIR = "XCurProcD"; +const FILE_BLOCKLIST = "blocklist.xml"; + +const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi; +const PREF_EM_CHECK_COMPATIBILITY_BASE = "extensions.checkCompatibility"; +var PREF_EM_CHECK_COMPATIBILITY; + +const TOOLKIT_ID = "toolkit@mozilla.org"; + +const VALID_TYPES_REGEXP = /^[\w\-]+$/; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AsyncShutdown.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Promise", + "resource://gre/modules/Promise.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository", + "resource://gre/modules/addons/AddonRepository.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "CertUtils", function certUtilsLazyGetter() { + let certUtils = {}; + Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils); + return certUtils; +}); + + +this.EXPORTED_SYMBOLS = [ "AddonManager", "AddonManagerPrivate" ]; + +const CATEGORY_PROVIDER_MODULE = "addon-provider-module"; + +// A list of providers to load by default +const DEFAULT_PROVIDERS = [ + "resource://gre/modules/addons/XPIProvider.jsm", + "resource://gre/modules/LightweightThemeManager.jsm" +]; + +Cu.import("resource://gre/modules/Log.jsm"); +// Configure a logger at the parent 'addons' level to format +// messages for all the modules under addons.* +const PARENT_LOGGER_ID = "addons"; +let parentLogger = Log.repository.getLogger(PARENT_LOGGER_ID); +parentLogger.level = Log.Level.Warn; +let formatter = new Log.BasicFormatter(); +// Set parent logger (and its children) to append to +// the Javascript section of the Browser Console +parentLogger.addAppender(new Log.ConsoleAppender(formatter)); +// Set parent logger (and its children) to +// also append to standard out +parentLogger.addAppender(new Log.DumpAppender(formatter)); + +// Create a new logger (child of 'addons' logger) +// for use by the Addons Manager +const LOGGER_ID = "addons.manager"; +let logger = Log.repository.getLogger(LOGGER_ID); + +// Provide the ability to enable/disable logging +// messages at runtime. +// If the "extensions.logging.enabled" preference is +// missing or 'false', messages at the WARNING and higher +// severity should be logged to the JS console and standard error. +// If "extensions.logging.enabled" is set to 'true', messages +// at DEBUG and higher should go to JS console and standard error. +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; + +const UNNAMED_PROVIDER = ""; +function providerName(aProvider) { + return aProvider.name || UNNAMED_PROVIDER; +} + +/** + * Preference listener which listens for a change in the + * "extensions.logging.enabled" preference and changes the logging level of the + * parent 'addons' level logger accordingly. + */ +var PrefObserver = { + init: function PrefObserver_init() { + Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); + Services.obs.addObserver(this, "xpcom-shutdown", false); + this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); + }, + + observe: function PrefObserver_observe(aSubject, aTopic, aData) { + if (aTopic == "xpcom-shutdown") { + Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); + Services.obs.removeObserver(this, "xpcom-shutdown"); + } + else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { + let debugLogEnabled = false; + try { + debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED); + } + catch (e) { + } + if (debugLogEnabled) { + parentLogger.level = Log.Level.Debug; + } + else { + parentLogger.level = Log.Level.Warn; + } + } + } +}; + +PrefObserver.init(); + +/** + * Calls a callback method consuming any thrown exception. Any parameters after + * the callback parameter will be passed to the callback. + * + * @param aCallback + * The callback method to call + */ +function safeCall(aCallback, ...aArgs) { + try { + aCallback.apply(null, aArgs); + } + catch (e) { + logger.warn("Exception calling callback", e); + } +} + +/** + * Report an exception thrown by a provider API method. + */ +function reportProviderError(aProvider, aMethod, aError) { + let method = `provider ${providerName(aProvider)}.${aMethod}`; + AddonManagerPrivate.recordException("AMI", method, aError); + logger.error("Exception calling " + method, aError); +} + +/** + * Calls a method on a provider if it exists and consumes any thrown exception. + * Any parameters after the aDefault parameter are passed to the provider's method. + * + * @param aProvider + * The provider to call + * @param aMethod + * The method name to call + * @param aDefault + * A default return value if the provider does not implement the named + * method or throws an error. + * @return the return value from the provider, or aDefault if the provider does not + * implement method or throws an error + */ +function callProvider(aProvider, aMethod, aDefault, ...aArgs) { + if (!(aMethod in aProvider)) + return aDefault; + + try { + return aProvider[aMethod].apply(aProvider, aArgs); + } + catch (e) { + reportProviderError(aProvider, aMethod, e); + return aDefault; + } +} + +/** + * Calls a method on a provider if it exists and consumes any thrown exception. + * Parameters after aMethod are passed to aProvider.aMethod(). + * The last parameter must be a callback function. + * If the provider does not implement the method, or the method throws, calls + * the callback with 'undefined'. + * + * @param aProvider + * The provider to call + * @param aMethod + * The method name to call + */ +function callProviderAsync(aProvider, aMethod, ...aArgs) { + let callback = aArgs[aArgs.length - 1]; + if (!(aMethod in aProvider)) { + callback(undefined); + return; + } + try { + return aProvider[aMethod].apply(aProvider, aArgs); + } + catch (e) { + reportProviderError(aProvider, aMethod, e); + callback(undefined); + return; + } +} + +/** + * Gets the currently selected locale for display. + * @return the selected locale or "en-US" if none is selected + */ +function getLocale() { + try { + if (Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE)) + return Services.locale.getLocaleComponentForUserAgent(); + } + catch (e) { } + + try { + let locale = Services.prefs.getComplexValue(PREF_SELECTED_LOCALE, + Ci.nsIPrefLocalizedString); + if (locale) + return locale; + } + catch (e) { } + + try { + return Services.prefs.getCharPref(PREF_SELECTED_LOCALE); + } + catch (e) { } + + return "en-US"; +} + +/** + * Previously the APIs for installing add-ons from webpages accepted nsIURI + * arguments for the installing page. They now take an nsIPrincipal but for now + * maintain backwards compatibility by converting an nsIURI to an nsIPrincipal. + * + * @param aPrincipalOrURI + * The argument passed to the API function. Can be null, an nsIURI or + * an nsIPrincipal. + * @return an nsIPrincipal. + */ +function ensurePrincipal(principalOrURI) { + if (principalOrURI instanceof Ci.nsIPrincipal) + return principalOrURI; + + logger.warn("Deprecated API call, please pass a non-null nsIPrincipal instead of an nsIURI"); + + // Previously a null installing URI meant allowing the install regardless. + if (!principalOrURI) { + return Services.scriptSecurityManager.getSystemPrincipal(); + } + + if (principalOrURI instanceof Ci.nsIURI) { + return Services.scriptSecurityManager.createCodebasePrincipal(principalOrURI, { + inBrowser: true + }); + } + + // Just return whatever we have, the API method will log an error about it. + return principalOrURI; +} + +/** + * A helper class to repeatedly call a listener with each object in an array + * optionally checking whether the object has a method in it. + * + * @param aObjects + * The array of objects to iterate through + * @param aMethod + * An optional method name, if not null any objects without this method + * will not be passed to the listener + * @param aListener + * A listener implementing nextObject and noMoreObjects methods. The + * former will be called with the AsyncObjectCaller as the first + * parameter and the object as the second. noMoreObjects will be passed + * just the AsyncObjectCaller + */ +function AsyncObjectCaller(aObjects, aMethod, aListener) { + this.objects = [...aObjects]; + this.method = aMethod; + this.listener = aListener; + + this.callNext(); +} + +AsyncObjectCaller.prototype = { + objects: null, + method: null, + listener: null, + + /** + * Passes the next object to the listener or calls noMoreObjects if there + * are none left. + */ + callNext: function AOC_callNext() { + if (this.objects.length == 0) { + this.listener.noMoreObjects(this); + return; + } + + let object = this.objects.shift(); + if (!this.method || this.method in object) + this.listener.nextObject(this, object); + else + this.callNext(); + } +}; + +/** + * Listens for a browser changing origin and cancels the installs that were + * started by it. + */ +function BrowserListener(aBrowser, aInstallingPrincipal, aInstalls) { + this.browser = aBrowser; + this.principal = aInstallingPrincipal; + this.installs = aInstalls; + this.installCount = aInstalls.length; + + aBrowser.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION); + Services.obs.addObserver(this, "message-manager-disconnect", true); + + for (let install of this.installs) + install.addListener(this); + + this.registered = true; +} + +BrowserListener.prototype = { + browser: null, + installs: null, + installCount: null, + registered: false, + + unregister: function() { + if (!this.registered) + return; + this.registered = false; + + Services.obs.removeObserver(this, "message-manager-disconnect"); + // The browser may have already been detached + if (this.browser.removeProgressListener) + this.browser.removeProgressListener(this); + + for (let install of this.installs) + install.removeListener(this); + this.installs = null; + }, + + cancelInstalls: function() { + for (let install of this.installs) { + try { + install.cancel(); + } + catch (e) { + // Some installs may have already failed or been cancelled, ignore these + } + } + }, + + observe: function(subject, topic, data) { + if (subject != this.browser.messageManager) + return; + + // The browser's message manager has closed and so the browser is + // going away, cancel all installs + this.cancelInstalls(); + }, + + onLocationChange: function(webProgress, request, location) { + if (this.browser.contentPrincipal && this.principal.subsumes(this.browser.contentPrincipal)) + return; + + // The browser has navigated to a new origin so cancel all installs + this.cancelInstalls(); + }, + + onDownloadCancelled: function(install) { + // Don't need to hear more events from this install + install.removeListener(this); + + // Once all installs have ended unregister everything + if (--this.installCount == 0) + this.unregister(); + }, + + onDownloadFailed: function(install) { + this.onDownloadCancelled(install); + }, + + onInstallFailed: function(install) { + this.onDownloadCancelled(install); + }, + + onInstallEnded: function(install) { + this.onDownloadCancelled(install); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, + Ci.nsIWebProgressListener, + Ci.nsIObserver]) +}; + +/** + * This represents an author of an add-on (e.g. creator or developer) + * + * @param aName + * The name of the author + * @param aURL + * The URL of the author's profile page + */ +function AddonAuthor(aName, aURL) { + this.name = aName; + this.url = aURL; +} + +AddonAuthor.prototype = { + name: null, + url: null, + + // Returns the author's name, defaulting to the empty string + toString: function AddonAuthor_toString() { + return this.name || ""; + } +} + +/** + * This represents an screenshot for an add-on + * + * @param aURL + * The URL to the full version of the screenshot + * @param aWidth + * The width in pixels of the screenshot + * @param aHeight + * The height in pixels of the screenshot + * @param aThumbnailURL + * The URL to the thumbnail version of the screenshot + * @param aThumbnailWidth + * The width in pixels of the thumbnail version of the screenshot + * @param aThumbnailHeight + * The height in pixels of the thumbnail version of the screenshot + * @param aCaption + * The caption of the screenshot + */ +function AddonScreenshot(aURL, aWidth, aHeight, aThumbnailURL, + aThumbnailWidth, aThumbnailHeight, aCaption) { + this.url = aURL; + if (aWidth) this.width = aWidth; + if (aHeight) this.height = aHeight; + if (aThumbnailURL) this.thumbnailURL = aThumbnailURL; + if (aThumbnailWidth) this.thumbnailWidth = aThumbnailWidth; + if (aThumbnailHeight) this.thumbnailHeight = aThumbnailHeight; + if (aCaption) this.caption = aCaption; +} + +AddonScreenshot.prototype = { + url: null, + width: null, + height: null, + thumbnailURL: null, + thumbnailWidth: null, + thumbnailHeight: null, + caption: null, + + // Returns the screenshot URL, defaulting to the empty string + toString: function AddonScreenshot_toString() { + return this.url || ""; + } +} + + +/** + * This represents a compatibility override for an addon. + * + * @param aType + * Overrride type - "compatible" or "incompatible" + * @param aMinVersion + * Minimum version of the addon to match + * @param aMaxVersion + * Maximum version of the addon to match + * @param aAppID + * Application ID used to match appMinVersion and appMaxVersion + * @param aAppMinVersion + * Minimum version of the application to match + * @param aAppMaxVersion + * Maximum version of the application to match + */ +function AddonCompatibilityOverride(aType, aMinVersion, aMaxVersion, aAppID, + aAppMinVersion, aAppMaxVersion) { + this.type = aType; + this.minVersion = aMinVersion; + this.maxVersion = aMaxVersion; + this.appID = aAppID; + this.appMinVersion = aAppMinVersion; + this.appMaxVersion = aAppMaxVersion; +} + +AddonCompatibilityOverride.prototype = { + /** + * Type of override - "incompatible" or "compatible". + * Only "incompatible" is supported for now. + */ + type: null, + + /** + * Min version of the addon to match. + */ + minVersion: null, + + /** + * Max version of the addon to match. + */ + maxVersion: null, + + /** + * Application ID to match. + */ + appID: null, + + /** + * Min version of the application to match. + */ + appMinVersion: null, + + /** + * Max version of the application to match. + */ + appMaxVersion: null +}; + + +/** + * A type of add-on, used by the UI to determine how to display different types + * of add-ons. + * + * @param aID + * The add-on type ID + * @param aLocaleURI + * The URI of a localized properties file to get the displayable name + * for the type from + * @param aLocaleKey + * The key for the string in the properties file or the actual display + * name if aLocaleURI is null. Include %ID% to include the type ID in + * the key + * @param aViewType + * The optional type of view to use in the UI + * @param aUIPriority + * The priority is used by the UI to list the types in order. Lower + * values push the type higher in the list. + * @param aFlags + * An option set of flags that customize the display of the add-on in + * the UI. + */ +function AddonType(aID, aLocaleURI, aLocaleKey, aViewType, aUIPriority, aFlags) { + if (!aID) + throw Components.Exception("An AddonType must have an ID", Cr.NS_ERROR_INVALID_ARG); + + if (aViewType && aUIPriority === undefined) + throw Components.Exception("An AddonType with a defined view must have a set UI priority", + Cr.NS_ERROR_INVALID_ARG); + + if (!aLocaleKey) + throw Components.Exception("An AddonType must have a displayable name", + Cr.NS_ERROR_INVALID_ARG); + + this.id = aID; + this.uiPriority = aUIPriority; + this.viewType = aViewType; + this.flags = aFlags; + + if (aLocaleURI) { + this.__defineGetter__("name", function nameGetter() { + delete this.name; + let bundle = Services.strings.createBundle(aLocaleURI); + this.name = bundle.GetStringFromName(aLocaleKey.replace("%ID%", aID)); + return this.name; + }); + } + else { + this.name = aLocaleKey; + } +} + +var gStarted = false; +var gStartupComplete = false; +var gCheckCompatibility = true; +var gStrictCompatibility = true; +var gCheckUpdateSecurityDefault = true; +var gCheckUpdateSecurity = gCheckUpdateSecurityDefault; +var gUpdateEnabled = true; +var gAutoUpdateDefault = true; +var gShutdownBarrier = null; +var gRepoShutdownState = ""; +var gShutdownInProgress = false; + +/** + * This is the real manager, kept here rather than in AddonManager to keep its + * contents hidden from API users. + */ +var AddonManagerInternal = { + managerListeners: [], + installListeners: [], + addonListeners: [], + typeListeners: [], + pendingProviders: new Set(), + providers: new Set(), + providerShutdowns: new Map(), + types: {}, + startupChanges: {}, + // Store telemetry details per addon provider + telemetryDetails: {}, + + // A read-only wrapper around the types dictionary + typesProxy: Proxy.create({ + getOwnPropertyDescriptor: function typesProxy_getOwnPropertyDescriptor(aName) { + if (!(aName in AddonManagerInternal.types)) + return undefined; + + return { + value: AddonManagerInternal.types[aName].type, + writable: false, + configurable: false, + enumerable: true + } + }, + + getPropertyDescriptor: function typesProxy_getPropertyDescriptor(aName) { + return this.getOwnPropertyDescriptor(aName); + }, + + getOwnPropertyNames: function typesProxy_getOwnPropertyNames() { + return Object.keys(AddonManagerInternal.types); + }, + + getPropertyNames: function typesProxy_getPropertyNames() { + return this.getOwnPropertyNames(); + }, + + delete: function typesProxy_delete(aName) { + // Not allowed to delete properties + return false; + }, + + defineProperty: function typesProxy_defineProperty(aName, aProperty) { + // Ignore attempts to define properties + }, + + fix: function typesProxy_fix(){ + return undefined; + }, + + // Despite MDC's claims to the contrary, it is required that this trap + // be defined + enumerate: function typesProxy_enumerate() { + // All properties are enumerable + return this.getPropertyNames(); + } + }), + + recordTimestamp: function AMI_recordTimestamp(name, value) { + this.TelemetryTimestamps.add(name, value); + }, + + validateBlocklist: function AMI_validateBlocklist() { + let appBlocklist = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]); + + // If there is no application shipped blocklist then there is nothing to do + if (!appBlocklist.exists()) + return; + + let profileBlocklist = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]); + + // If there is no blocklist in the profile then copy the application shipped + // one there + if (!profileBlocklist.exists()) { + try { + appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); + } + catch (e) { + logger.warn("Failed to copy the application shipped blocklist to the profile", e); + } + return; + } + + let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + try { + let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Ci.nsIConverterInputStream); + fileStream.init(appBlocklist, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); + cstream.init(fileStream, "UTF-8", 0, 0); + + let data = ""; + let str = {}; + let read = 0; + do { + read = cstream.readString(0xffffffff, str); + data += str.value; + } while (read != 0); + + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); + var doc = parser.parseFromString(data, "text/xml"); + } + catch (e) { + logger.warn("Application shipped blocklist could not be loaded", e); + return; + } + finally { + try { + fileStream.close(); + } + catch (e) { + logger.warn("Unable to close blocklist file stream", e); + } + } + + // If the namespace is incorrect then ignore the application shipped + // blocklist + if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) { + logger.warn("Application shipped blocklist has an unexpected namespace (" + + doc.documentElement.namespaceURI + ")"); + return; + } + + // If there is no lastupdate information then ignore the application shipped + // blocklist + if (!doc.documentElement.hasAttribute("lastupdate")) + return; + + // If the application shipped blocklist is older than the profile blocklist + // then do nothing + if (doc.documentElement.getAttribute("lastupdate") <= + profileBlocklist.lastModifiedTime) + return; + + // Otherwise copy the application shipped blocklist to the profile + try { + appBlocklist.copyTo(profileBlocklist.parent, FILE_BLOCKLIST); + } + catch (e) { + logger.warn("Failed to copy the application shipped blocklist to the profile", e); + } + }, + + /** + * Start up a provider, and register its shutdown hook if it has one + */ + _startProvider(aProvider, aAppChanged, aOldAppVersion, aOldPlatformVersion) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + logger.debug(`Starting provider: ${providerName(aProvider)}`); + callProvider(aProvider, "startup", null, aAppChanged, aOldAppVersion, aOldPlatformVersion); + if ('shutdown' in aProvider) { + let name = providerName(aProvider); + let AMProviderShutdown = () => { + // If the provider has been unregistered, it will have been removed from + // this.providers. If it hasn't been unregistered, then this is a normal + // shutdown - and we move it to this.pendingProviders incase we're + // running in a test that will start AddonManager again. + if (this.providers.has(aProvider)) { + this.providers.delete(aProvider); + this.pendingProviders.add(aProvider); + } + + return new Promise((resolve, reject) => { + logger.debug("Calling shutdown blocker for " + name); + resolve(aProvider.shutdown()); + }) + .catch(err => { + logger.warn("Failure during shutdown of " + name, err); + AddonManagerPrivate.recordException("AMI", "Async shutdown of " + name, err); + }); + }; + logger.debug("Registering shutdown blocker for " + name); + this.providerShutdowns.set(aProvider, AMProviderShutdown); + AddonManager.shutdown.addBlocker(name, AMProviderShutdown); + } + + this.pendingProviders.delete(aProvider); + this.providers.add(aProvider); + logger.debug(`Provider finished startup: ${providerName(aProvider)}`); + }, + + /** + * Initializes the AddonManager, loading any known providers and initializing + * them. + */ + startup: function AMI_startup() { + try { + if (gStarted) + return; + + this.recordTimestamp("AMI_startup_begin"); + + // clear this for xpcshell test restarts + for (let provider in this.telemetryDetails) + delete this.telemetryDetails[provider]; + + let appChanged = undefined; + + let oldAppVersion = null; + try { + oldAppVersion = Services.prefs.getCharPref(PREF_EM_LAST_APP_VERSION); + appChanged = Services.appinfo.version != oldAppVersion; + } + catch (e) { } + + let oldPlatformVersion = null; + try { + oldPlatformVersion = Services.prefs.getCharPref(PREF_EM_LAST_PLATFORM_VERSION); + } + catch (e) { } + + if (appChanged !== false) { + logger.debug("Application has been upgraded"); + Services.prefs.setCharPref(PREF_EM_LAST_APP_VERSION, + Services.appinfo.version); + Services.prefs.setCharPref(PREF_EM_LAST_PLATFORM_VERSION, + Services.appinfo.platformVersion); + Services.prefs.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION, + (appChanged === undefined ? 0 : -1)); + this.validateBlocklist(); + } + + PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." + + Services.appinfo.version.replace(BRANCH_REGEXP, "$1"); + + try { + gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_CHECK_COMPATIBILITY, this, false); + + try { + gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_STRICT_COMPATIBILITY, this, false); + + try { + let defaultBranch = Services.prefs.getDefaultBranch(""); + gCheckUpdateSecurityDefault = defaultBranch.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch(e) {} + + try { + gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_CHECK_UPDATE_SECURITY, this, false); + + try { + gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_UPDATE_ENABLED, this, false); + + try { + gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); + } catch (e) {} + Services.prefs.addObserver(PREF_EM_AUTOUPDATE_DEFAULT, this, false); + + let defaultProvidersEnabled = true; + try { + defaultProvidersEnabled = Services.prefs.getBoolPref(PREF_DEFAULT_PROVIDERS_ENABLED); + } catch (e) {} + AddonManagerPrivate.recordSimpleMeasure("default_providers", defaultProvidersEnabled); + + // Ensure all default providers have had a chance to register themselves + if (defaultProvidersEnabled) { + for (let url of DEFAULT_PROVIDERS) { + try { + let scope = {}; + Components.utils.import(url, scope); + // Sanity check - make sure the provider exports a symbol that + // has a 'startup' method + let syms = Object.keys(scope); + if ((syms.length < 1) || + (typeof scope[syms[0]].startup != "function")) { + logger.warn("Provider " + url + " has no startup()"); + AddonManagerPrivate.recordException("AMI", "provider " + url, "no startup()"); + } + logger.debug("Loaded provider scope for " + url + ": " + Object.keys(scope).toSource()); + } + catch (e) { + AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); + logger.error("Exception loading default provider \"" + url + "\"", e); + } + }; + } + + // Load any providers registered in the category manager + let catman = Cc["@mozilla.org/categorymanager;1"]. + getService(Ci.nsICategoryManager); + let entries = catman.enumerateCategory(CATEGORY_PROVIDER_MODULE); + while (entries.hasMoreElements()) { + let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; + let url = catman.getCategoryEntry(CATEGORY_PROVIDER_MODULE, entry); + + try { + Components.utils.import(url, {}); + logger.debug(`Loaded provider scope for ${url}`); + } + catch (e) { + AddonManagerPrivate.recordException("AMI", "provider " + url + " load failed", e); + logger.error("Exception loading provider " + entry + " from category \"" + + url + "\"", e); + } + } + + // Register our shutdown handler with the AsyncShutdown manager + gShutdownBarrier = new AsyncShutdown.Barrier("AddonManager: Waiting for providers to shut down."); + AsyncShutdown.profileBeforeChange.addBlocker("AddonManager: shutting down.", + this.shutdownManager.bind(this), + {fetchState: this.shutdownState.bind(this)}); + + // Once we start calling providers we must allow all normal methods to work. + gStarted = true; + + for (let provider of this.pendingProviders) { + this._startProvider(provider, appChanged, oldAppVersion, oldPlatformVersion); + } + + // If this is a new profile just pretend that there were no changes + if (appChanged === undefined) { + for (let type in this.startupChanges) + delete this.startupChanges[type]; + } + + gStartupComplete = true; + this.recordTimestamp("AMI_startup_end"); + } + catch (e) { + logger.error("startup failed", e); + AddonManagerPrivate.recordException("AMI", "startup failed", e); + } + + logger.debug("Completed startup sequence"); + this.callManagerListeners("onStartup"); + }, + + /** + * Registers a new AddonProvider. + * + * @param aProvider + * The provider to register + * @param aTypes + * An optional array of add-on types + */ + registerProvider: function AMI_registerProvider(aProvider, aTypes) { + if (!aProvider || typeof aProvider != "object") + throw Components.Exception("aProvider must be specified", + Cr.NS_ERROR_INVALID_ARG); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + this.pendingProviders.add(aProvider); + + if (aTypes) { + aTypes.forEach(function(aType) { + if (!(aType.id in this.types)) { + if (!VALID_TYPES_REGEXP.test(aType.id)) { + logger.warn("Ignoring invalid type " + aType.id); + return; + } + + this.types[aType.id] = { + type: aType, + providers: [aProvider] + }; + + let typeListeners = this.typeListeners.slice(0); + for (let listener of typeListeners) { + safeCall(function listenerSafeCall() { + listener.onTypeAdded(aType); + }); + } + } + else { + this.types[aType.id].providers.push(aProvider); + } + }, this); + } + + // If we're registering after startup call this provider's startup. + if (gStarted) { + this._startProvider(aProvider); + } + }, + + /** + * Unregisters an AddonProvider. + * + * @param aProvider + * The provider to unregister + * @return Whatever the provider's 'shutdown' method returns (if anything). + * For providers that have async shutdown methods returning Promises, + * the caller should wait for that Promise to resolve. + */ + unregisterProvider: function AMI_unregisterProvider(aProvider) { + if (!aProvider || typeof aProvider != "object") + throw Components.Exception("aProvider must be specified", + Cr.NS_ERROR_INVALID_ARG); + + this.providers.delete(aProvider); + // The test harness will unregister XPIProvider *after* shutdown, which is + // after the provider will have been moved from providers to + // pendingProviders. + this.pendingProviders.delete(aProvider); + + for (let type in this.types) { + this.types[type].providers = this.types[type].providers.filter(function filterProvider(p) p != aProvider); + if (this.types[type].providers.length == 0) { + let oldType = this.types[type].type; + delete this.types[type]; + + let typeListeners = this.typeListeners.slice(0); + for (let listener of typeListeners) { + safeCall(function listenerSafeCall() { + listener.onTypeRemoved(oldType); + }); + } + } + } + + // If we're unregistering after startup but before shutting down, + // remove the blocker for this provider's shutdown and call it. + // If we're already shutting down, just let gShutdownBarrier call it to avoid races. + if (gStarted && !gShutdownInProgress) { + logger.debug("Unregistering shutdown blocker for " + providerName(aProvider)); + let shutter = this.providerShutdowns.get(aProvider); + if (shutter) { + this.providerShutdowns.delete(aProvider); + gShutdownBarrier.client.removeBlocker(shutter); + return shutter(); + } + } + return undefined; + }, + + /** + * Mark a provider as safe to access via AddonManager APIs, before its + * startup has completed. + * + * Normally a provider isn't marked as safe until after its (synchronous) + * startup() method has returned. Until a provider has been marked safe, + * it won't be used by any of the AddonManager APIs. markProviderSafe() + * allows a provider to mark itself as safe during its startup; this can be + * useful if the provider wants to perform tasks that block startup, which + * happen after its required initialization tasks and therefore when the + * provider is in a safe state. + * + * @param aProvider Provider object to mark safe + */ + markProviderSafe: function AMI_markProviderSafe(aProvider) { + if (!gStarted) { + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + } + + if (!aProvider || typeof aProvider != "object") { + throw Components.Exception("aProvider must be specified", + Cr.NS_ERROR_INVALID_ARG); + } + + if (!this.pendingProviders.has(aProvider)) { + return; + } + + this.pendingProviders.delete(aProvider); + this.providers.add(aProvider); + }, + + /** + * Calls a method on all registered providers if it exists and consumes any + * thrown exception. Return values are ignored. Any parameters after the + * method parameter are passed to the provider's method. + * WARNING: Do not use for asynchronous calls; callProviders() does not + * invoke callbacks if provider methods throw synchronous exceptions. + * + * @param aMethod + * The method name to call + * @see callProvider + */ + callProviders: function AMI_callProviders(aMethod, ...aArgs) { + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + try { + if (aMethod in provider) + provider[aMethod].apply(provider, aArgs); + } + catch (e) { + reportProviderError(aProvider, aMethod, e); + } + } + }, + + /** + * Report the current state of asynchronous shutdown + */ + shutdownState() { + let state = []; + if (gShutdownBarrier) { + state.push({ + name: gShutdownBarrier.client.name, + state: gShutdownBarrier.state + }); + } + state.push({ + name: "AddonRepository: async shutdown", + state: gRepoShutdownState + }); + return state; + }, + + /** + * Shuts down the addon manager and all registered providers, this must clean + * up everything in order for automated tests to fake restarts. + * @return Promise{null} that resolves when all providers and dependent modules + * have finished shutting down + */ + shutdownManager: Task.async(function* () { + logger.debug("shutdown"); + this.callManagerListeners("onShutdown"); + + gRepoShutdownState = "pending"; + gShutdownInProgress = true; + // Clean up listeners + Services.prefs.removeObserver(PREF_EM_CHECK_COMPATIBILITY, this); + Services.prefs.removeObserver(PREF_EM_STRICT_COMPATIBILITY, this); + Services.prefs.removeObserver(PREF_EM_CHECK_UPDATE_SECURITY, this); + Services.prefs.removeObserver(PREF_EM_UPDATE_ENABLED, this); + Services.prefs.removeObserver(PREF_EM_AUTOUPDATE_DEFAULT, this); + + let savedError = null; + // Only shut down providers if they've been started. + if (gStarted) { + try { + yield gShutdownBarrier.wait(); + } + catch(err) { + savedError = err; + logger.error("Failure during wait for shutdown barrier", err); + AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonManager providers", err); + } + } + + // Shut down AddonRepository after providers (if any). + try { + gRepoShutdownState = "in progress"; + yield AddonRepository.shutdown(); + gRepoShutdownState = "done"; + } + catch(err) { + savedError = err; + logger.error("Failure during AddonRepository shutdown", err); + AddonManagerPrivate.recordException("AMI", "Async shutdown of AddonRepository", err); + } + + logger.debug("Async provider shutdown done"); + this.managerListeners.splice(0, this.managerListeners.length); + this.installListeners.splice(0, this.installListeners.length); + this.addonListeners.splice(0, this.addonListeners.length); + this.typeListeners.splice(0, this.typeListeners.length); + this.providerShutdowns.clear(); + for (let type in this.startupChanges) + delete this.startupChanges[type]; + gStarted = false; + gStartupComplete = false; + gShutdownBarrier = null; + gShutdownInProgress = false; + if (savedError) { + throw savedError; + } + }), + + /** + * Notified when a preference we're interested in has changed. + * + * @see nsIObserver + */ + observe: function AMI_observe(aSubject, aTopic, aData) { + switch (aData) { + case PREF_EM_CHECK_COMPATIBILITY: { + let oldValue = gCheckCompatibility; + try { + gCheckCompatibility = Services.prefs.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); + } catch(e) { + gCheckCompatibility = true; + } + + this.callManagerListeners("onCompatibilityModeChanged"); + + if (gCheckCompatibility != oldValue) + this.updateAddonAppDisabledStates(); + + break; + } + case PREF_EM_STRICT_COMPATIBILITY: { + let oldValue = gStrictCompatibility; + try { + gStrictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY); + } catch(e) { + gStrictCompatibility = true; + } + + this.callManagerListeners("onCompatibilityModeChanged"); + + if (gStrictCompatibility != oldValue) + this.updateAddonAppDisabledStates(); + + break; + } + case PREF_EM_CHECK_UPDATE_SECURITY: { + let oldValue = gCheckUpdateSecurity; + try { + gCheckUpdateSecurity = Services.prefs.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch(e) { + gCheckUpdateSecurity = true; + } + + this.callManagerListeners("onCheckUpdateSecurityChanged"); + + if (gCheckUpdateSecurity != oldValue) + this.updateAddonAppDisabledStates(); + + break; + } + case PREF_EM_UPDATE_ENABLED: { + let oldValue = gUpdateEnabled; + try { + gUpdateEnabled = Services.prefs.getBoolPref(PREF_EM_UPDATE_ENABLED); + } catch(e) { + gUpdateEnabled = true; + } + + this.callManagerListeners("onUpdateModeChanged"); + break; + } + case PREF_EM_AUTOUPDATE_DEFAULT: { + let oldValue = gAutoUpdateDefault; + try { + gAutoUpdateDefault = Services.prefs.getBoolPref(PREF_EM_AUTOUPDATE_DEFAULT); + } catch(e) { + gAutoUpdateDefault = true; + } + + this.callManagerListeners("onUpdateModeChanged"); + break; + } + } + }, + + /** + * Replaces %...% strings in an addon url (update and updateInfo) with + * appropriate values. + * + * @param aAddon + * The Addon representing the add-on + * @param aUri + * The string representation of the URI to escape + * @param aAppVersion + * The optional application version to use for %APP_VERSION% + * @return The appropriately escaped URI. + */ + escapeAddonURI: function AMI_escapeAddonURI(aAddon, aUri, aAppVersion) + { + if (!aAddon || typeof aAddon != "object") + throw Components.Exception("aAddon must be an Addon object", + Cr.NS_ERROR_INVALID_ARG); + + if (!aUri || typeof aUri != "string") + throw Components.Exception("aUri must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aAppVersion && typeof aAppVersion != "string") + throw Components.Exception("aAppVersion must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + var addonStatus = aAddon.userDisabled || aAddon.softDisabled ? "userDisabled" + : "userEnabled"; + + if (!aAddon.isCompatible) + addonStatus += ",incompatible"; + if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) + addonStatus += ",blocklisted"; + if (aAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) + addonStatus += ",softblocked"; + + try { + var xpcomABI = Services.appinfo.XPCOMABI; + } catch (ex) { + xpcomABI = UNKNOWN_XPCOM_ABI; + } + + let uri = aUri.replace(/%ITEM_ID%/g, aAddon.id); + uri = uri.replace(/%ITEM_VERSION%/g, aAddon.version); + uri = uri.replace(/%ITEM_STATUS%/g, addonStatus); + uri = uri.replace(/%APP_ID%/g, Services.appinfo.ID); + uri = uri.replace(/%APP_VERSION%/g, aAppVersion ? aAppVersion : + Services.appinfo.version); + uri = uri.replace(/%REQ_VERSION%/g, UPDATE_REQUEST_VERSION); + uri = uri.replace(/%APP_OS%/g, Services.appinfo.OS); + uri = uri.replace(/%APP_ABI%/g, xpcomABI); + uri = uri.replace(/%APP_LOCALE%/g, getLocale()); + uri = uri.replace(/%CURRENT_APP_VERSION%/g, Services.appinfo.version); + + // Replace custom parameters (names of custom parameters must have at + // least 3 characters to prevent lookups for something like %D0%C8) + var catMan = null; + uri = uri.replace(/%(\w{3,})%/g, function parameterReplace(aMatch, aParam) { + if (!catMan) { + catMan = Cc["@mozilla.org/categorymanager;1"]. + getService(Ci.nsICategoryManager); + } + + try { + var contractID = catMan.getCategoryEntry(CATEGORY_UPDATE_PARAMS, aParam); + var paramHandler = Cc[contractID].getService(Ci.nsIPropertyBag2); + return paramHandler.getPropertyAsAString(aParam); + } + catch(e) { + return aMatch; + } + }); + + // escape() does not properly encode + symbols in any embedded FVF strings. + return uri.replace(/\+/g, "%2B"); + }, + + /** + * Performs a background update check by starting an update for all add-ons + * that can be updated. + * @return Promise{null} Resolves when the background update check is complete + * (the resulting addon installations may still be in progress). + */ + backgroundUpdateCheck: function AMI_backgroundUpdateCheck() { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + let buPromise = Task.spawn(function* backgroundUpdateTask() { + logger.debug("Background update check beginning"); + + Services.obs.notifyObservers(null, "addons-background-update-start", null); + + if (this.updateEnabled) { + let scope = {}; + Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", scope); + scope.LightweightThemeManager.updateCurrentTheme(); + + let allAddons = yield new Promise((resolve, reject) => this.getAllAddons(resolve)); + + // Repopulate repository cache first, to ensure compatibility overrides + // are up to date before checking for addon updates. + yield AddonRepository.backgroundUpdateCheck(); + + // Keep track of all the async add-on updates happening in parallel + let updates = []; + + for (let addon of allAddons) { + // Check all add-ons for updates so that any compatibility updates will + // be applied + updates.push(new Promise((resolve, reject) => { + addon.findUpdates({ + onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) { + // Start installing updates when the add-on can be updated and + // background updates should be applied. + logger.debug("Found update for add-on ${id}", aAddon); + if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE && + AddonManager.shouldAutoUpdate(aAddon)) { + // XXX we really should resolve when this install is done, + // not when update-available check completes, no? + logger.debug("Starting install of ${id}", aAddon); + aInstall.install(); + } + }, + + onUpdateFinished: aAddon => { logger.debug("onUpdateFinished for ${id}", aAddon); resolve(); } + }, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE); + })); + } + yield Promise.all(updates); + } + + logger.debug("Background update check complete"); + Services.obs.notifyObservers(null, + "addons-background-update-complete", + null); + }.bind(this)); + // Fork the promise chain so we can log the error and let our caller see it too. + buPromise.then(null, e => logger.warn("Error in background update", e)); + return buPromise; + }, + + /** + * Adds a add-on to the list of detected changes for this startup. If + * addStartupChange is called multiple times for the same add-on in the same + * startup then only the most recent change will be remembered. + * + * @param aType + * The type of change as a string. Providers can define their own + * types of changes or use the existing defined STARTUP_CHANGE_* + * constants + * @param aID + * The ID of the add-on + */ + addStartupChange: function AMI_addStartupChange(aType, aID) { + if (!aType || typeof aType != "string") + throw Components.Exception("aType must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (!aID || typeof aID != "string") + throw Components.Exception("aID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (gStartupComplete) + return; + + // Ensure that an ID is only listed in one type of change + for (let type in this.startupChanges) + this.removeStartupChange(type, aID); + + if (!(aType in this.startupChanges)) + this.startupChanges[aType] = []; + this.startupChanges[aType].push(aID); + }, + + /** + * Removes a startup change for an add-on. + * + * @param aType + * The type of change + * @param aID + * The ID of the add-on + */ + removeStartupChange: function AMI_removeStartupChange(aType, aID) { + if (!aType || typeof aType != "string") + throw Components.Exception("aType must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (!aID || typeof aID != "string") + throw Components.Exception("aID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (gStartupComplete) + return; + + if (!(aType in this.startupChanges)) + return; + + this.startupChanges[aType] = this.startupChanges[aType].filter( + function filterItem(aItem) aItem != aID); + }, + + /** + * Calls all registered AddonManagerListeners with an event. Any parameters + * after the method parameter are passed to the listener. + * + * @param aMethod + * The method on the listeners to call + */ + callManagerListeners: function AMI_callManagerListeners(aMethod, ...aArgs) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let managerListeners = this.managerListeners.slice(0); + for (let listener of managerListeners) { + try { + if (aMethod in listener) + listener[aMethod].apply(listener, aArgs); + } + catch (e) { + logger.warn("AddonManagerListener threw exception when calling " + aMethod, e); + } + } + }, + + /** + * Calls all registered InstallListeners with an event. Any parameters after + * the extraListeners parameter are passed to the listener. + * + * @param aMethod + * The method on the listeners to call + * @param aExtraListeners + * An optional array of extra InstallListeners to also call + * @return false if any of the listeners returned false, true otherwise + */ + callInstallListeners: function AMI_callInstallListeners(aMethod, + aExtraListeners, ...aArgs) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aExtraListeners && !Array.isArray(aExtraListeners)) + throw Components.Exception("aExtraListeners must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + let result = true; + let listeners; + if (aExtraListeners) + listeners = aExtraListeners.concat(this.installListeners); + else + listeners = this.installListeners.slice(0); + + for (let listener of listeners) { + try { + if (aMethod in listener) { + if (listener[aMethod].apply(listener, aArgs) === false) + result = false; + } + } + catch (e) { + logger.warn("InstallListener threw exception when calling " + aMethod, e); + } + } + return result; + }, + + /** + * Calls all registered AddonListeners with an event. Any parameters after + * the method parameter are passed to the listener. + * + * @param aMethod + * The method on the listeners to call + */ + callAddonListeners: function AMI_callAddonListeners(aMethod, ...aArgs) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMethod || typeof aMethod != "string") + throw Components.Exception("aMethod must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let addonListeners = this.addonListeners.slice(0); + for (let listener of addonListeners) { + try { + if (aMethod in listener) + listener[aMethod].apply(listener, aArgs); + } + catch (e) { + logger.warn("AddonListener threw exception when calling " + aMethod, e); + } + } + }, + + /** + * Notifies all providers that an add-on has been enabled when that type of + * add-on only supports a single add-on being enabled at a time. This allows + * the providers to disable theirs if necessary. + * + * @param aID + * The ID of the enabled add-on + * @param aType + * The type of the enabled add-on + * @param aPendingRestart + * A boolean indicating if the change will only take place the next + * time the application is restarted + */ + notifyAddonChanged: function AMI_notifyAddonChanged(aID, aType, aPendingRestart) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aID && typeof aID != "string") + throw Components.Exception("aID must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (!aType || typeof aType != "string") + throw Components.Exception("aType must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + // Temporary hack until bug 520124 lands. + // We can get here during synchronous startup, at which point it's + // considered unsafe (and therefore disallowed by AddonManager.jsm) to + // access providers that haven't been initialized yet. Since this is when + // XPIProvider is starting up, XPIProvider can't access itself via APIs + // going through AddonManager.jsm. Furthermore, LightweightThemeManager may + // not be initialized until after XPIProvider is, and therefore would also + // be unaccessible during XPIProvider startup. Thankfully, these are the + // only two uses of this API, and we know it's safe to use this API with + // both providers; so we have this hack to allow bypassing the normal + // safetey guard. + // The notifyAddonChanged/addonChanged API will be unneeded and therefore + // removed by bug 520124, so this is a temporary quick'n'dirty hack. + let providers = [...this.providers, ...this.pendingProviders]; + for (let provider of providers) { + callProvider(provider, "addonChanged", null, aID, aType, aPendingRestart); + } + }, + + /** + * Notifies all providers they need to update the appDisabled property for + * their add-ons in response to an application change such as a blocklist + * update. + */ + updateAddonAppDisabledStates: function AMI_updateAddonAppDisabledStates() { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + this.callProviders("updateAddonAppDisabledStates"); + }, + + /** + * Notifies all providers that the repository has updated its data for + * installed add-ons. + * + * @param aCallback + * Function to call when operation is complete. + */ + updateAddonRepositoryData: function AMI_updateAddonRepositoryData(aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", { + nextObject: function updateAddonRepositoryData_nextObject(aCaller, aProvider) { + callProviderAsync(aProvider, "updateAddonRepositoryData", + aCaller.callNext.bind(aCaller)); + }, + noMoreObjects: function updateAddonRepositoryData_noMoreObjects(aCaller) { + safeCall(aCallback); + // only tests should care about this + Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated", null); + } + }); + }, + + /** + * Asynchronously gets an AddonInstall for a URL. + * + * @param aUrl + * The string represenation of the URL the add-on is located at + * @param aCallback + * A callback to pass the AddonInstall to + * @param aMimetype + * The mimetype of the add-on + * @param aHash + * An optional hash of the add-on + * @param aName + * An optional placeholder name while the add-on is being downloaded + * @param aIcons + * Optional placeholder icons while the add-on is being downloaded + * @param aVersion + * An optional placeholder version while the add-on is being downloaded + * @param aLoadGroup + * An optional nsILoadGroup to associate any network requests with + * @throws if the aUrl, aCallback or aMimetype arguments are not specified + */ + getInstallForURL: function AMI_getInstallForURL(aUrl, aCallback, aMimetype, + aHash, aName, aIcons, + aVersion, aBrowser) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aUrl || typeof aUrl != "string") + throw Components.Exception("aURL must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aHash && typeof aHash != "string") + throw Components.Exception("aHash must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (aName && typeof aName != "string") + throw Components.Exception("aName must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (aIcons) { + if (typeof aIcons == "string") + aIcons = { "32": aIcons }; + else if (typeof aIcons != "object") + throw Components.Exception("aIcons must be a string, an object or null", + Cr.NS_ERROR_INVALID_ARG); + } else { + aIcons = {}; + } + + if (aVersion && typeof aVersion != "string") + throw Components.Exception("aVersion must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + if (aBrowser && (!(aBrowser instanceof Ci.nsIDOMElement))) + throw Components.Exception("aBrowser must be a nsIDOMElement or null", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + if (callProvider(provider, "supportsMimetype", false, aMimetype)) { + callProviderAsync(provider, "getInstallForURL", + aUrl, aHash, aName, aIcons, aVersion, aBrowser, + function getInstallForURL_safeCall(aInstall) { + safeCall(aCallback, aInstall); + }); + return; + } + } + safeCall(aCallback, null); + }, + + /** + * Asynchronously gets an AddonInstall for an nsIFile. + * + * @param aFile + * The nsIFile where the add-on is located + * @param aCallback + * A callback to pass the AddonInstall to + * @param aMimetype + * An optional mimetype hint for the add-on + * @throws if the aFile or aCallback arguments are not specified + */ + getInstallForFile: function AMI_getInstallForFile(aFile, aCallback, aMimetype) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!(aFile instanceof Ci.nsIFile)) + throw Components.Exception("aFile must be a nsIFile", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + if (aMimetype && typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a string or null", + Cr.NS_ERROR_INVALID_ARG); + + new AsyncObjectCaller(this.providers, "getInstallForFile", { + nextObject: function getInstallForFile_nextObject(aCaller, aProvider) { + callProviderAsync(aProvider, "getInstallForFile", aFile, + function getInstallForFile_safeCall(aInstall) { + if (aInstall) + safeCall(aCallback, aInstall); + else + aCaller.callNext(); + }); + }, + + noMoreObjects: function getInstallForFile_noMoreObjects(aCaller) { + safeCall(aCallback, null); + } + }); + }, + + /** + * Asynchronously gets all current AddonInstalls optionally limiting to a list + * of types. + * + * @param aTypes + * An optional array of types to retrieve. Each type is a string name + * @param aCallback + * A callback which will be passed an array of AddonInstalls + * @throws If the aCallback argument is not specified + */ + getInstallsByTypes: function AMI_getInstallsByTypes(aTypes, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + let installs = []; + + new AsyncObjectCaller(this.providers, "getInstallsByTypes", { + nextObject: function getInstallsByTypes_nextObject(aCaller, aProvider) { + callProviderAsync(aProvider, "getInstallsByTypes", aTypes, + function getInstallsByTypes_safeCall(aProviderInstalls) { + if (aProviderInstalls) { + installs = installs.concat(aProviderInstalls); + } + aCaller.callNext(); + }); + }, + + noMoreObjects: function getInstallsByTypes_noMoreObjects(aCaller) { + safeCall(aCallback, installs); + } + }); + }, + + /** + * Asynchronously gets all current AddonInstalls. + * + * @param aCallback + * A callback which will be passed an array of AddonInstalls + */ + getAllInstalls: function AMI_getAllInstalls(aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + this.getInstallsByTypes(null, aCallback); + }, + + /** + * Synchronously map a URI to the corresponding Addon ID. + * + * Mappable URIs are limited to in-application resources belonging to the + * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc. + * but do not include URIs from meta data, such as the add-on homepage. + * + * @param aURI + * nsIURI to map to an addon id + * @return string containing the Addon ID or null + * @see amIAddonManager.mapURIToAddonID + */ + mapURIToAddonID: function AMI_mapURIToAddonID(aURI) { + if (!(aURI instanceof Ci.nsIURI)) { + throw Components.Exception("aURI is not a nsIURI", + Cr.NS_ERROR_INVALID_ARG); + } + + // Try all providers + let providers = [...this.providers]; + for (let provider of providers) { + var id = callProvider(provider, "mapURIToAddonID", null, aURI); + if (id !== null) { + return id; + } + } + + return null; + }, + + /** + * Checks whether installation is enabled for a particular mimetype. + * + * @param aMimetype + * The mimetype to check + * @return true if installation is enabled for the mimetype + */ + isInstallEnabled: function AMI_isInstallEnabled(aMimetype) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + if (callProvider(provider, "supportsMimetype", false, aMimetype) && + callProvider(provider, "isInstallEnabled")) + return true; + } + return false; + }, + + /** + * Checks whether a particular source is allowed to install add-ons of a + * given mimetype. + * + * @param aMimetype + * The mimetype of the add-on + * @param aInstallingPrincipal + * The nsIPrincipal that initiated the install + * @return true if the source is allowed to install this mimetype + */ + isInstallAllowed: function AMI_isInstallAllowed(aMimetype, aInstallingPrincipal) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (!aInstallingPrincipal || !(aInstallingPrincipal instanceof Ci.nsIPrincipal)) + throw Components.Exception("aInstallingPrincipal must be a nsIPrincipal", + Cr.NS_ERROR_INVALID_ARG); + + let providers = [...this.providers]; + for (let provider of providers) { + if (callProvider(provider, "supportsMimetype", false, aMimetype) && + callProvider(provider, "isInstallAllowed", null, aInstallingPrincipal)) + return true; + } + return false; + }, + + /** + * Starts installation of an array of AddonInstalls notifying the registered + * web install listener of blocked or started installs. + * + * @param aMimetype + * The mimetype of add-ons being installed + * @param aBrowser + * The optional browser element that started the installs + * @param aInstallingPrincipal + * The nsIPrincipal that initiated the install + * @param aInstalls + * The array of AddonInstalls to be installed + */ + installAddonsFromWebpage: function AMI_installAddonsFromWebpage(aMimetype, + aBrowser, + aInstallingPrincipal, + aInstalls) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aMimetype || typeof aMimetype != "string") + throw Components.Exception("aMimetype must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (aBrowser && !(aBrowser instanceof Ci.nsIDOMElement)) + throw Components.Exception("aSource must be a nsIDOMElement, or null", + Cr.NS_ERROR_INVALID_ARG); + + if (!aInstallingPrincipal || !(aInstallingPrincipal instanceof Ci.nsIPrincipal)) + throw Components.Exception("aInstallingPrincipal must be a nsIPrincipal", + Cr.NS_ERROR_INVALID_ARG); + + if (!Array.isArray(aInstalls)) + throw Components.Exception("aInstalls must be an array", + Cr.NS_ERROR_INVALID_ARG); + + if (!("@mozilla.org/addons/web-install-listener;1" in Cc)) { + logger.warn("No web installer available, cancelling all installs"); + aInstalls.forEach(function(aInstall) { + aInstall.cancel(); + }); + return; + } + + // When a chrome in-content UI has loaded a inside to host a + // website we want to do our security checks on the inner-browser but + // notify front-end that install events came from the outer-browser (the + // main tab's browser). Check this by seeing if the browser we've been + // passed is in a content type docshell and if so get the outer-browser. + let topBrowser = aBrowser; + let docShell = aBrowser.ownerDocument.defaultView + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIDocShellTreeItem); + if (docShell.itemType == Ci.nsIDocShellTreeItem.typeContent) + topBrowser = docShell.chromeEventHandler; + + try { + let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"]. + getService(Ci.amIWebInstallListener); + + if (!this.isInstallEnabled(aMimetype)) { + for (let install of aInstalls) + install.cancel(); + + weblistener.onWebInstallDisabled(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length); + return; + } + else if (!aBrowser.contentPrincipal || !aInstallingPrincipal.subsumes(aBrowser.contentPrincipal)) { + for (let install of aInstalls) + install.cancel(); + + if (weblistener instanceof Ci.amIWebInstallListener2) { + weblistener.onWebInstallOriginBlocked(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length); + } + return; + } + + // The installs may start now depending on the web install listener, + // listen for the browser navigating to a new origin and cancel the + // installs in that case. + new BrowserListener(aBrowser, aInstallingPrincipal, aInstalls); + + if (!this.isInstallAllowed(aMimetype, aInstallingPrincipal)) { + if (weblistener.onWebInstallBlocked(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length)) { + aInstalls.forEach(function(aInstall) { + aInstall.install(); + }); + } + } + else if (weblistener.onWebInstallRequested(topBrowser, aInstallingPrincipal.URI, + aInstalls, aInstalls.length)) { + aInstalls.forEach(function(aInstall) { + aInstall.install(); + }); + } + } + catch (e) { + // In the event that the weblistener throws during instantiation or when + // calling onWebInstallBlocked or onWebInstallRequested all of the + // installs should get cancelled. + logger.warn("Failure calling web installer", e); + aInstalls.forEach(function(aInstall) { + aInstall.cancel(); + }); + } + }, + + /** + * Adds a new InstallListener if the listener is not already registered. + * + * @param aListener + * The InstallListener to add + */ + addInstallListener: function AMI_addInstallListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a InstallListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.installListeners.some(function addInstallListener_matchListener(i) { + return i == aListener; })) + this.installListeners.push(aListener); + }, + + /** + * Removes an InstallListener if the listener is registered. + * + * @param aListener + * The InstallListener to remove + */ + removeInstallListener: function AMI_removeInstallListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a InstallListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.installListeners.length) { + if (this.installListeners[pos] == aListener) + this.installListeners.splice(pos, 1); + else + pos++; + } + }, + + /** + * Asynchronously gets an add-on with a specific ID. + * + * @param aID + * The ID of the add-on to retrieve + * @param aCallback + * The callback to pass the retrieved add-on to + * @throws if the aID or aCallback arguments are not specified + */ + getAddonByID: function AMI_getAddonByID(aID, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aID || typeof aID != "string") + throw Components.Exception("aID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + new AsyncObjectCaller(this.providers, "getAddonByID", { + nextObject: function getAddonByID_nextObject(aCaller, aProvider) { + callProviderAsync(aProvider, "getAddonByID", aID, + function getAddonByID_safeCall(aAddon) { + if (aAddon) + safeCall(aCallback, aAddon); + else + aCaller.callNext(); + }); + }, + + noMoreObjects: function getAddonByID_noMoreObjects(aCaller) { + safeCall(aCallback, null); + } + }); + }, + + /** + * Asynchronously get an add-on with a specific Sync GUID. + * + * @param aGUID + * String GUID of add-on to retrieve + * @param aCallback + * The callback to pass the retrieved add-on to. + * @throws if the aGUID or aCallback arguments are not specified + */ + getAddonBySyncGUID: function AMI_getAddonBySyncGUID(aGUID, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!aGUID || typeof aGUID != "string") + throw Components.Exception("aGUID must be a non-empty string", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + new AsyncObjectCaller(this.providers, "getAddonBySyncGUID", { + nextObject: function getAddonBySyncGUID_nextObject(aCaller, aProvider) { + callProviderAsync(aProvider, "getAddonBySyncGUID", aGUID, + function getAddonBySyncGUID_safeCall(aAddon) { + if (aAddon) { + safeCall(aCallback, aAddon); + } else { + aCaller.callNext(); + } + }); + }, + + noMoreObjects: function getAddonBySyncGUID_noMoreObjects(aCaller) { + safeCall(aCallback, null); + } + }); + }, + + /** + * Asynchronously gets an array of add-ons. + * + * @param aIDs + * The array of IDs to retrieve + * @param aCallback + * The callback to pass an array of Addons to + * @throws if the aID or aCallback arguments are not specified + */ + getAddonsByIDs: function AMI_getAddonsByIDs(aIDs, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (!Array.isArray(aIDs)) + throw Components.Exception("aIDs must be an array", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + let addons = []; + + new AsyncObjectCaller(aIDs, null, { + nextObject: function getAddonsByIDs_nextObject(aCaller, aID) { + AddonManagerInternal.getAddonByID(aID, + function getAddonsByIDs_getAddonByID(aAddon) { + addons.push(aAddon); + aCaller.callNext(); + }); + }, + + noMoreObjects: function getAddonsByIDs_noMoreObjects(aCaller) { + safeCall(aCallback, addons); + } + }); + }, + + /** + * Asynchronously gets add-ons of specific types. + * + * @param aTypes + * An optional array of types to retrieve. Each type is a string name + * @param aCallback + * The callback to pass an array of Addons to. + * @throws if the aCallback argument is not specified + */ + getAddonsByTypes: function AMI_getAddonsByTypes(aTypes, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + let addons = []; + + new AsyncObjectCaller(this.providers, "getAddonsByTypes", { + nextObject: function getAddonsByTypes_nextObject(aCaller, aProvider) { + callProviderAsync(aProvider, "getAddonsByTypes", aTypes, + function getAddonsByTypes_concatAddons(aProviderAddons) { + if (aProviderAddons) { + addons = addons.concat(aProviderAddons); + } + aCaller.callNext(); + }); + }, + + noMoreObjects: function getAddonsByTypes_noMoreObjects(aCaller) { + safeCall(aCallback, addons); + } + }); + }, + + /** + * Asynchronously gets all installed add-ons. + * + * @param aCallback + * A callback which will be passed an array of Addons + */ + getAllAddons: function AMI_getAllAddons(aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + this.getAddonsByTypes(null, aCallback); + }, + + /** + * Asynchronously gets add-ons that have operations waiting for an application + * restart to complete. + * + * @param aTypes + * An optional array of types to retrieve. Each type is a string name + * @param aCallback + * The callback to pass the array of Addons to + * @throws if the aCallback argument is not specified + */ + getAddonsWithOperationsByTypes: + function AMI_getAddonsWithOperationsByTypes(aTypes, aCallback) { + if (!gStarted) + throw Components.Exception("AddonManager is not initialized", + Cr.NS_ERROR_NOT_INITIALIZED); + + if (aTypes && !Array.isArray(aTypes)) + throw Components.Exception("aTypes must be an array or null", + Cr.NS_ERROR_INVALID_ARG); + + if (typeof aCallback != "function") + throw Components.Exception("aCallback must be a function", + Cr.NS_ERROR_INVALID_ARG); + + let addons = []; + + new AsyncObjectCaller(this.providers, "getAddonsWithOperationsByTypes", { + nextObject: function getAddonsWithOperationsByTypes_nextObject + (aCaller, aProvider) { + callProviderAsync(aProvider, "getAddonsWithOperationsByTypes", aTypes, + function getAddonsWithOperationsByTypes_concatAddons + (aProviderAddons) { + if (aProviderAddons) { + addons = addons.concat(aProviderAddons); + } + aCaller.callNext(); + }); + }, + + noMoreObjects: function getAddonsWithOperationsByTypes_noMoreObjects(caller) { + safeCall(aCallback, addons); + } + }); + }, + + /** + * Adds a new AddonManagerListener if the listener is not already registered. + * + * @param aListener + * The listener to add + */ + addManagerListener: function AMI_addManagerListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonManagerListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.managerListeners.some(function addManagerListener_matchListener(i) { + return i == aListener; })) + this.managerListeners.push(aListener); + }, + + /** + * Removes an AddonManagerListener if the listener is registered. + * + * @param aListener + * The listener to remove + */ + removeManagerListener: function AMI_removeManagerListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonManagerListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.managerListeners.length) { + if (this.managerListeners[pos] == aListener) + this.managerListeners.splice(pos, 1); + else + pos++; + } + }, + + /** + * Adds a new AddonListener if the listener is not already registered. + * + * @param aListener + * The AddonListener to add + */ + addAddonListener: function AMI_addAddonListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.addonListeners.some(function addAddonListener_matchListener(i) { + return i == aListener; })) + this.addonListeners.push(aListener); + }, + + /** + * Removes an AddonListener if the listener is registered. + * + * @param aListener + * The AddonListener to remove + */ + removeAddonListener: function AMI_removeAddonListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be an AddonListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.addonListeners.length) { + if (this.addonListeners[pos] == aListener) + this.addonListeners.splice(pos, 1); + else + pos++; + } + }, + + /** + * Adds a new TypeListener if the listener is not already registered. + * + * @param aListener + * The TypeListener to add + */ + addTypeListener: function AMI_addTypeListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a TypeListener object", + Cr.NS_ERROR_INVALID_ARG); + + if (!this.typeListeners.some(function addTypeListener_matchListener(i) { + return i == aListener; })) + this.typeListeners.push(aListener); + }, + + /** + * Removes an TypeListener if the listener is registered. + * + * @param aListener + * The TypeListener to remove + */ + removeTypeListener: function AMI_removeTypeListener(aListener) { + if (!aListener || typeof aListener != "object") + throw Components.Exception("aListener must be a TypeListener object", + Cr.NS_ERROR_INVALID_ARG); + + let pos = 0; + while (pos < this.typeListeners.length) { + if (this.typeListeners[pos] == aListener) + this.typeListeners.splice(pos, 1); + else + pos++; + } + }, + + get addonTypes() { + return this.typesProxy; + }, + + get autoUpdateDefault() { + return gAutoUpdateDefault; + }, + + set autoUpdateDefault(aValue) { + aValue = !!aValue; + if (aValue != gAutoUpdateDefault) + Services.prefs.setBoolPref(PREF_EM_AUTOUPDATE_DEFAULT, aValue); + return aValue; + }, + + get checkCompatibility() { + return gCheckCompatibility; + }, + + set checkCompatibility(aValue) { + aValue = !!aValue; + if (aValue != gCheckCompatibility) { + if (!aValue) + Services.prefs.setBoolPref(PREF_EM_CHECK_COMPATIBILITY, false); + else + Services.prefs.clearUserPref(PREF_EM_CHECK_COMPATIBILITY); + } + return aValue; + }, + + get strictCompatibility() { + return gStrictCompatibility; + }, + + set strictCompatibility(aValue) { + aValue = !!aValue; + if (aValue != gStrictCompatibility) + Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, aValue); + return aValue; + }, + + get checkUpdateSecurityDefault() { + return gCheckUpdateSecurityDefault; + }, + + get checkUpdateSecurity() { + return gCheckUpdateSecurity; + }, + + set checkUpdateSecurity(aValue) { + aValue = !!aValue; + if (aValue != gCheckUpdateSecurity) { + if (aValue != gCheckUpdateSecurityDefault) + Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, aValue); + else + Services.prefs.clearUserPref(PREF_EM_CHECK_UPDATE_SECURITY); + } + return aValue; + }, + + get updateEnabled() { + return gUpdateEnabled; + }, + + set updateEnabled(aValue) { + aValue = !!aValue; + if (aValue != gUpdateEnabled) + Services.prefs.setBoolPref(PREF_EM_UPDATE_ENABLED, aValue); + return aValue; + }, +}; + +/** + * Should not be used outside of core Mozilla code. This is a private API for + * the startup and platform integration code to use. Refer to the methods on + * AddonManagerInternal for documentation however note that these methods are + * subject to change at any time. + */ +this.AddonManagerPrivate = { + startup: function AMP_startup() { + AddonManagerInternal.startup(); + }, + + registerProvider: function AMP_registerProvider(aProvider, aTypes) { + AddonManagerInternal.registerProvider(aProvider, aTypes); + }, + + unregisterProvider: function AMP_unregisterProvider(aProvider) { + AddonManagerInternal.unregisterProvider(aProvider); + }, + + markProviderSafe: function AMP_markProviderSafe(aProvider) { + AddonManagerInternal.markProviderSafe(aProvider); + }, + + backgroundUpdateCheck: function AMP_backgroundUpdateCheck() { + return AddonManagerInternal.backgroundUpdateCheck(); + }, + + backgroundUpdateTimerHandler() { + // Don't call through to the real update check if no checks are enabled. + if (!AddonManagerInternal.updateEnabled) { + logger.info("Skipping background update check"); + return; + } + // Don't return the promise here, since the caller doesn't care. + AddonManagerInternal.backgroundUpdateCheck(); + }, + + addStartupChange: function AMP_addStartupChange(aType, aID) { + AddonManagerInternal.addStartupChange(aType, aID); + }, + + removeStartupChange: function AMP_removeStartupChange(aType, aID) { + AddonManagerInternal.removeStartupChange(aType, aID); + }, + + notifyAddonChanged: function AMP_notifyAddonChanged(aID, aType, aPendingRestart) { + AddonManagerInternal.notifyAddonChanged(aID, aType, aPendingRestart); + }, + + updateAddonAppDisabledStates: function AMP_updateAddonAppDisabledStates() { + AddonManagerInternal.updateAddonAppDisabledStates(); + }, + + updateAddonRepositoryData: function AMP_updateAddonRepositoryData(aCallback) { + AddonManagerInternal.updateAddonRepositoryData(aCallback); + }, + + callInstallListeners: function AMP_callInstallListeners(...aArgs) { + return AddonManagerInternal.callInstallListeners.apply(AddonManagerInternal, + aArgs); + }, + + callAddonListeners: function AMP_callAddonListeners(...aArgs) { + AddonManagerInternal.callAddonListeners.apply(AddonManagerInternal, aArgs); + }, + + AddonAuthor: AddonAuthor, + + AddonScreenshot: AddonScreenshot, + + AddonCompatibilityOverride: AddonCompatibilityOverride, + + AddonType: AddonType, + + recordTimestamp: function AMP_recordTimestamp(name, value) { + AddonManagerInternal.recordTimestamp(name, value); + }, + + _simpleMeasures: {}, + recordSimpleMeasure: function AMP_recordSimpleMeasure(name, value) { + this._simpleMeasures[name] = value; + }, + + recordException: function AMP_recordException(aModule, aContext, aException) { + let report = { + module: aModule, + context: aContext + }; + + if (typeof aException == "number") { + report.message = Components.Exception("", aException).name; + } + else { + report.message = aException.toString(); + if (aException.fileName) { + report.file = aException.fileName; + report.line = aException.lineNumber; + } + } + + this._simpleMeasures.exception = report; + }, + + getSimpleMeasures: function AMP_getSimpleMeasures() { + return this._simpleMeasures; + }, + + getTelemetryDetails: function AMP_getTelemetryDetails() { + return AddonManagerInternal.telemetryDetails; + }, + + setTelemetryDetails: function AMP_setTelemetryDetails(aProvider, aDetails) { + AddonManagerInternal.telemetryDetails[aProvider] = aDetails; + }, + + // Start a timer, record a simple measure of the time interval when + // timer.done() is called + simpleTimer: function(aName) { + let startTime = Cu.now(); + return { + done: () => this.recordSimpleMeasure(aName, Math.round(Cu.now() - startTime)) + }; + }, + + /** + * Helper to call update listeners when no update is available. + * + * This can be used as an implementation for Addon.findUpdates() when + * no update mechanism is available. + */ + callNoUpdateListeners: function (addon, listener, reason, appVersion, platformVersion) { + if ("onNoCompatibilityUpdateAvailable" in listener) { + safeCall(listener.onNoCompatibilityUpdateAvailable.bind(listener), addon); + } + if ("onNoUpdateAvailable" in listener) { + safeCall(listener.onNoUpdateAvailable.bind(listener), addon); + } + if ("onUpdateFinished" in listener) { + safeCall(listener.onUpdateFinished.bind(listener), addon); + } + }, +}; + +/** + * This is the public API that UI and developers should be calling. All methods + * just forward to AddonManagerInternal. + */ +this.AddonManager = { + // Constants for the AddonInstall.state property + // The install is available for download. + STATE_AVAILABLE: 0, + // The install is being downloaded. + STATE_DOWNLOADING: 1, + // The install is checking for compatibility information. + STATE_CHECKING: 2, + // The install is downloaded and ready to install. + STATE_DOWNLOADED: 3, + // The download failed. + STATE_DOWNLOAD_FAILED: 4, + // The add-on is being installed. + STATE_INSTALLING: 5, + // The add-on has been installed. + STATE_INSTALLED: 6, + // The install failed. + STATE_INSTALL_FAILED: 7, + // The install has been cancelled. + STATE_CANCELLED: 8, + + // Constants representing different types of errors while downloading an + // add-on. + // The download failed due to network problems. + ERROR_NETWORK_FAILURE: -1, + // The downloaded file did not match the provided hash. + ERROR_INCORRECT_HASH: -2, + // The downloaded file seems to be corrupted in some way. + ERROR_CORRUPT_FILE: -3, + // An error occured trying to write to the filesystem. + ERROR_FILE_ACCESS: -4, + // The downloaded file seems to be WebExtension. + ERROR_WEBEXT_FILE: -5, + + // These must be kept in sync with AddonUpdateChecker. + // No error was encountered. + UPDATE_STATUS_NO_ERROR: 0, + // The update check timed out + UPDATE_STATUS_TIMEOUT: -1, + // There was an error while downloading the update information. + UPDATE_STATUS_DOWNLOAD_ERROR: -2, + // The update information was malformed in some way. + UPDATE_STATUS_PARSE_ERROR: -3, + // The update information was not in any known format. + UPDATE_STATUS_UNKNOWN_FORMAT: -4, + // The update information was not correctly signed or there was an SSL error. + UPDATE_STATUS_SECURITY_ERROR: -5, + // The update was cancelled. + UPDATE_STATUS_CANCELLED: -6, + + // Constants to indicate why an update check is being performed + // Update check has been requested by the user. + UPDATE_WHEN_USER_REQUESTED: 1, + // Update check is necessary to see if the Addon is compatibile with a new + // version of the application. + UPDATE_WHEN_NEW_APP_DETECTED: 2, + // Update check is necessary because a new application has been installed. + UPDATE_WHEN_NEW_APP_INSTALLED: 3, + // Update check is a regular background update check. + UPDATE_WHEN_PERIODIC_UPDATE: 16, + // Update check is needed to check an Addon that is being installed. + UPDATE_WHEN_ADDON_INSTALLED: 17, + + // Constants for operations in Addon.pendingOperations + // Indicates that the Addon has no pending operations. + PENDING_NONE: 0, + // Indicates that the Addon will be enabled after the application restarts. + PENDING_ENABLE: 1, + // Indicates that the Addon will be disabled after the application restarts. + PENDING_DISABLE: 2, + // Indicates that the Addon will be uninstalled after the application restarts. + PENDING_UNINSTALL: 4, + // Indicates that the Addon will be installed after the application restarts. + PENDING_INSTALL: 8, + PENDING_UPGRADE: 16, + + // Constants for operations in Addon.operationsRequiringRestart + // Indicates that restart isn't required for any operation. + OP_NEEDS_RESTART_NONE: 0, + // Indicates that restart is required for enabling the addon. + OP_NEEDS_RESTART_ENABLE: 1, + // Indicates that restart is required for disabling the addon. + OP_NEEDS_RESTART_DISABLE: 2, + // Indicates that restart is required for uninstalling the addon. + OP_NEEDS_RESTART_UNINSTALL: 4, + // Indicates that restart is required for installing the addon. + OP_NEEDS_RESTART_INSTALL: 8, + + // Constants for permissions in Addon.permissions. + // Indicates that the Addon can be uninstalled. + PERM_CAN_UNINSTALL: 1, + // Indicates that the Addon can be enabled by the user. + PERM_CAN_ENABLE: 2, + // Indicates that the Addon can be disabled by the user. + PERM_CAN_DISABLE: 4, + // Indicates that the Addon can be upgraded. + PERM_CAN_UPGRADE: 8, + // Indicates that the Addon can be set to be optionally enabled + // on a case-by-case basis. + PERM_CAN_ASK_TO_ACTIVATE: 16, + + // General descriptions of where items are installed. + // Installed in this profile. + SCOPE_PROFILE: 1, + // Installed for all of this user's profiles. + SCOPE_USER: 2, + // Installed and owned by the application. + SCOPE_APPLICATION: 4, + // Installed for all users of the computer. + SCOPE_SYSTEM: 8, + // The combination of all scopes. + SCOPE_ALL: 15, + + // Add-on type is expected to be displayed in the UI in a list. + VIEW_TYPE_LIST: "list", + + // Constants describing how add-on types behave. + + // If no add-ons of a type are installed, then the category for that add-on + // type should be hidden in the UI. + TYPE_UI_HIDE_EMPTY: 16, + // Indicates that this add-on type supports the ask-to-activate state. + // That is, add-ons of this type can be set to be optionally enabled + // on a case-by-case basis. + TYPE_SUPPORTS_ASK_TO_ACTIVATE: 32, + // The add-on type natively supports undo for restartless uninstalls. + // If this flag is not specified, the UI is expected to handle this via + // disabling the add-on, and performing the actual uninstall at a later time. + TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL: 64, + + // Constants for Addon.applyBackgroundUpdates. + // Indicates that the Addon should not update automatically. + AUTOUPDATE_DISABLE: 0, + // Indicates that the Addon should update automatically only if + // that's the global default. + AUTOUPDATE_DEFAULT: 1, + // Indicates that the Addon should update automatically. + AUTOUPDATE_ENABLE: 2, + + // Constants for how Addon options should be shown. + // Options will be opened in a new window + OPTIONS_TYPE_DIALOG: 1, + // Options will be displayed within the AM detail view + OPTIONS_TYPE_INLINE: 2, + // Options will be displayed in a new tab, if possible + OPTIONS_TYPE_TAB: 3, + // Same as OPTIONS_TYPE_INLINE, but no Preferences button will be shown. + // Used to indicate that only non-interactive information will be shown. + OPTIONS_TYPE_INLINE_INFO: 4, + + // Constants for displayed or hidden options notifications + // Options notification will be displayed + OPTIONS_NOTIFICATION_DISPLAYED: "addon-options-displayed", + // Options notification will be hidden + OPTIONS_NOTIFICATION_HIDDEN: "addon-options-hidden", + + // Constants for getStartupChanges, addStartupChange and removeStartupChange + // Add-ons that were detected as installed during startup. Doesn't include + // add-ons that were pending installation the last time the application ran. + STARTUP_CHANGE_INSTALLED: "installed", + // Add-ons that were detected as changed during startup. This includes an + // add-on moving to a different location, changing version or just having + // been detected as possibly changed. + STARTUP_CHANGE_CHANGED: "changed", + // Add-ons that were detected as uninstalled during startup. Doesn't include + // add-ons that were pending uninstallation the last time the application ran. + STARTUP_CHANGE_UNINSTALLED: "uninstalled", + // Add-ons that were detected as disabled during startup, normally because of + // an application change making an add-on incompatible. Doesn't include + // add-ons that were pending being disabled the last time the application ran. + STARTUP_CHANGE_DISABLED: "disabled", + // Add-ons that were detected as enabled during startup, normally because of + // an application change making an add-on compatible. Doesn't include + // add-ons that were pending being enabled the last time the application ran. + STARTUP_CHANGE_ENABLED: "enabled", + + // Constants for the Addon.userDisabled property + // Indicates that the userDisabled state of this add-on is currently + // ask-to-activate. That is, it can be conditionally enabled on a + // case-by-case basis. + STATE_ASK_TO_ACTIVATE: "askToActivate", + +#ifdef MOZ_EM_DEBUG + get __AddonManagerInternal__() { + return AddonManagerInternal; + }, +#endif + + get isReady() { + return gStartupComplete && !gShutdownInProgress; + }, + + getInstallForURL: function AM_getInstallForURL(aUrl, aCallback, aMimetype, + aHash, aName, aIcons, + aVersion, aBrowser) { + AddonManagerInternal.getInstallForURL(aUrl, aCallback, aMimetype, aHash, + aName, aIcons, aVersion, aBrowser); + }, + + getInstallForFile: function AM_getInstallForFile(aFile, aCallback, aMimetype) { + AddonManagerInternal.getInstallForFile(aFile, aCallback, aMimetype); + }, + + /** + * Gets an array of add-on IDs that changed during the most recent startup. + * + * @param aType + * The type of startup change to get + * @return An array of add-on IDs + */ + getStartupChanges: function AM_getStartupChanges(aType) { + if (!(aType in AddonManagerInternal.startupChanges)) + return []; + return AddonManagerInternal.startupChanges[aType].slice(0); + }, + + getAddonByID: function AM_getAddonByID(aID, aCallback) { + AddonManagerInternal.getAddonByID(aID, aCallback); + }, + + getAddonBySyncGUID: function AM_getAddonBySyncGUID(aGUID, aCallback) { + AddonManagerInternal.getAddonBySyncGUID(aGUID, aCallback); + }, + + getAddonsByIDs: function AM_getAddonsByIDs(aIDs, aCallback) { + AddonManagerInternal.getAddonsByIDs(aIDs, aCallback); + }, + + getAddonsWithOperationsByTypes: + function AM_getAddonsWithOperationsByTypes(aTypes, aCallback) { + AddonManagerInternal.getAddonsWithOperationsByTypes(aTypes, aCallback); + }, + + getAddonsByTypes: function AM_getAddonsByTypes(aTypes, aCallback) { + AddonManagerInternal.getAddonsByTypes(aTypes, aCallback); + }, + + getAllAddons: function AM_getAllAddons(aCallback) { + AddonManagerInternal.getAllAddons(aCallback); + }, + + getInstallsByTypes: function AM_getInstallsByTypes(aTypes, aCallback) { + AddonManagerInternal.getInstallsByTypes(aTypes, aCallback); + }, + + getAllInstalls: function AM_getAllInstalls(aCallback) { + AddonManagerInternal.getAllInstalls(aCallback); + }, + + mapURIToAddonID: function AM_mapURIToAddonID(aURI) { + return AddonManagerInternal.mapURIToAddonID(aURI); + }, + + isInstallEnabled: function AM_isInstallEnabled(aType) { + return AddonManagerInternal.isInstallEnabled(aType); + }, + + isInstallAllowed: function AM_isInstallAllowed(aType, aInstallingPrincipal) { + return AddonManagerInternal.isInstallAllowed(aType, ensurePrincipal(aInstallingPrincipal)); + }, + + installAddonsFromWebpage: function AM_installAddonsFromWebpage(aType, aBrowser, + aInstallingPrincipal, + aInstalls) { + AddonManagerInternal.installAddonsFromWebpage(aType, aBrowser, + ensurePrincipal(aInstallingPrincipal), + aInstalls); + }, + + addManagerListener: function AM_addManagerListener(aListener) { + AddonManagerInternal.addManagerListener(aListener); + }, + + removeManagerListener: function AM_removeManagerListener(aListener) { + AddonManagerInternal.removeManagerListener(aListener); + }, + + addInstallListener: function AM_addInstallListener(aListener) { + AddonManagerInternal.addInstallListener(aListener); + }, + + removeInstallListener: function AM_removeInstallListener(aListener) { + AddonManagerInternal.removeInstallListener(aListener); + }, + + addAddonListener: function AM_addAddonListener(aListener) { + AddonManagerInternal.addAddonListener(aListener); + }, + + removeAddonListener: function AM_removeAddonListener(aListener) { + AddonManagerInternal.removeAddonListener(aListener); + }, + + addTypeListener: function AM_addTypeListener(aListener) { + AddonManagerInternal.addTypeListener(aListener); + }, + + removeTypeListener: function AM_removeTypeListener(aListener) { + AddonManagerInternal.removeTypeListener(aListener); + }, + + get addonTypes() { + return AddonManagerInternal.addonTypes; + }, + + /** + * Determines whether an Addon should auto-update or not. + * + * @param aAddon + * The Addon representing the add-on + * @return true if the addon should auto-update, false otherwise. + */ + shouldAutoUpdate: function AM_shouldAutoUpdate(aAddon) { + if (!aAddon || typeof aAddon != "object") + throw Components.Exception("aAddon must be specified", + Cr.NS_ERROR_INVALID_ARG); + + if (!("applyBackgroundUpdates" in aAddon)) + return false; + if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE) + return true; + if (aAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE) + return false; + return this.autoUpdateDefault; + }, + + get checkCompatibility() { + return AddonManagerInternal.checkCompatibility; + }, + + set checkCompatibility(aValue) { + AddonManagerInternal.checkCompatibility = aValue; + }, + + get strictCompatibility() { + return AddonManagerInternal.strictCompatibility; + }, + + set strictCompatibility(aValue) { + AddonManagerInternal.strictCompatibility = aValue; + }, + + get checkUpdateSecurityDefault() { + return AddonManagerInternal.checkUpdateSecurityDefault; + }, + + get checkUpdateSecurity() { + return AddonManagerInternal.checkUpdateSecurity; + }, + + set checkUpdateSecurity(aValue) { + AddonManagerInternal.checkUpdateSecurity = aValue; + }, + + get updateEnabled() { + return AddonManagerInternal.updateEnabled; + }, + + set updateEnabled(aValue) { + AddonManagerInternal.updateEnabled = aValue; + }, + + get autoUpdateDefault() { + return AddonManagerInternal.autoUpdateDefault; + }, + + set autoUpdateDefault(aValue) { + AddonManagerInternal.autoUpdateDefault = aValue; + }, + + escapeAddonURI: function AM_escapeAddonURI(aAddon, aUri, aAppVersion) { + return AddonManagerInternal.escapeAddonURI(aAddon, aUri, aAppVersion); + }, + + get shutdown() { + return gShutdownBarrier.client; + }, +}; + +// load the timestamps module into AddonManagerInternal +Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", AddonManagerInternal); +Object.freeze(AddonManagerInternal); +Object.freeze(AddonManagerPrivate); +Object.freeze(AddonManager); diff --git a/toolkit/mozapps/extensions/AddonPathService.cpp b/toolkit/mozapps/extensions/AddonPathService.cpp new file mode 100644 index 000000000..e384926fd --- /dev/null +++ b/toolkit/mozapps/extensions/AddonPathService.cpp @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "AddonPathService.h" + +#include "amIAddonManager.h" +#include "nsIURI.h" +#include "nsXULAppAPI.h" +#include "jsapi.h" +#include "nsServiceManagerUtils.h" +#include "nsLiteralString.h" +#include "nsThreadUtils.h" +#include "nsIIOService.h" +#include "nsNetUtil.h" +#include "nsIResProtocolHandler.h" +#include "nsIChromeRegistry.h" +#include "nsIJARURI.h" +#include "nsJSUtils.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/AddonPathService.h" +#include "mozilla/Omnijar.h" + +#include + +namespace mozilla { + +struct PathEntryComparator +{ + typedef AddonPathService::PathEntry PathEntry; + + bool Equals(const PathEntry& entry1, const PathEntry& entry2) const + { + return entry1.mPath == entry2.mPath; + } + + bool LessThan(const PathEntry& entry1, const PathEntry& entry2) const + { + return entry1.mPath < entry2.mPath; + } +}; + +AddonPathService::AddonPathService() +{ +} + +AddonPathService::~AddonPathService() +{ + sInstance = nullptr; +} + +NS_IMPL_ISUPPORTS(AddonPathService, amIAddonPathService) + +AddonPathService *AddonPathService::sInstance; + +/* static */ AddonPathService* +AddonPathService::GetInstance() +{ + if (!sInstance) { + sInstance = new AddonPathService(); + } + NS_ADDREF(sInstance); + return sInstance; +} + +JSAddonId* +AddonPathService::Find(const nsAString& path) +{ + // Use binary search to find the nearest entry that is <= |path|. + PathEntryComparator comparator; + unsigned index = mPaths.IndexOfFirstElementGt(PathEntry(path, nullptr), comparator); + if (index == 0) { + return nullptr; + } + const PathEntry& entry = mPaths[index - 1]; + + // Return the entry's addon if its path is a prefix of |path|. + if (StringBeginsWith(path, entry.mPath)) { + return entry.mAddonId; + } + return nullptr; +} + +NS_IMETHODIMP +AddonPathService::FindAddonId(const nsAString& path, nsAString& addonIdString) +{ + if (JSAddonId* id = Find(path)) { + JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id)); + AssignJSFlatString(addonIdString, flat); + } + return NS_OK; +} + +/* static */ JSAddonId* +AddonPathService::FindAddonId(const nsAString& path) +{ + // If no service has been created, then we're not going to find anything. + if (!sInstance) { + return nullptr; + } + + return sInstance->Find(path); +} + +NS_IMETHODIMP +AddonPathService::InsertPath(const nsAString& path, const nsAString& addonIdString) +{ + AutoSafeJSContext cx; + JS::RootedString str(cx, JS_NewUCStringCopyN(cx, + addonIdString.BeginReading(), + addonIdString.Length())); + JSAddonId* addonId = JS::NewAddonId(cx, str); + + // Add the new path in sorted order. + PathEntryComparator comparator; + mPaths.InsertElementSorted(PathEntry(path, addonId), comparator); + return NS_OK; +} + +static nsresult +ResolveURI(nsIURI* aURI, nsAString& out) +{ + bool equals; + nsresult rv; + nsCOMPtr uri; + nsAutoCString spec; + + // Resolve resource:// URIs. At the end of this if/else block, we + // have both spec and uri variables identifying the same URI. + if (NS_SUCCEEDED(aURI->SchemeIs("resource", &equals)) && equals) { + nsCOMPtr ioService = do_GetIOService(&rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr ph; + rv = ioService->GetProtocolHandler("resource", getter_AddRefs(ph)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr irph(do_QueryInterface(ph, &rv)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + rv = irph->ResolveURI(aURI, spec); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + rv = ioService->NewURI(spec, nullptr, nullptr, getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + } else if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &equals)) && equals) { + nsCOMPtr chromeReg = + mozilla::services::GetChromeRegistryService(); + if (NS_WARN_IF(!chromeReg)) + return NS_ERROR_UNEXPECTED; + + rv = chromeReg->ConvertChromeURL(aURI, getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + } else { + uri = aURI; + } + + if (NS_SUCCEEDED(uri->SchemeIs("jar", &equals)) && equals) { + nsCOMPtr jarURI = do_QueryInterface(uri, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr jarFileURI; + rv = jarURI->GetJARFile(getter_AddRefs(jarFileURI)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + return ResolveURI(jarFileURI, out); + } + + if (NS_SUCCEEDED(uri->SchemeIs("file", &equals)) && equals) { + nsCOMPtr baseFileURL = do_QueryInterface(uri, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + nsCOMPtr file; + rv = baseFileURL->GetFile(getter_AddRefs(file)); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + + return file->GetPath(out); + } + return NS_ERROR_FAILURE; +} + +JSAddonId* +MapURIToAddonID(nsIURI* aURI) +{ + if (!NS_IsMainThread() || XRE_GetProcessType() != GoannaProcessType_Default) { + return nullptr; + } + + nsAutoString filePath; + nsresult rv = ResolveURI(aURI, filePath); + if (NS_FAILED(rv)) + return nullptr; + + nsCOMPtr greJar = Omnijar::GetPath(Omnijar::GRE); + nsCOMPtr appJar = Omnijar::GetPath(Omnijar::APP); + if (greJar && appJar) { + nsAutoString greJarString, appJarString; + if (NS_FAILED(greJar->GetPath(greJarString)) || NS_FAILED(appJar->GetPath(appJarString))) + return nullptr; + + // If |aURI| is part of either Omnijar, then it can't be part of an + // add-on. This catches pretty much all URLs for Firefox content. + if (filePath.Equals(greJarString) || filePath.Equals(appJarString)) + return nullptr; + } + + // If it's not part of Firefox, we resort to binary searching through the + // add-on paths. + return AddonPathService::FindAddonId(filePath); +} + +} diff --git a/toolkit/mozapps/extensions/AddonPathService.h b/toolkit/mozapps/extensions/AddonPathService.h new file mode 100644 index 000000000..f739b018f --- /dev/null +++ b/toolkit/mozapps/extensions/AddonPathService.h @@ -0,0 +1,55 @@ +//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef AddonPathService_h +#define AddonPathService_h + +#include "amIAddonPathService.h" +#include "nsString.h" +#include "nsTArray.h" + +class nsIURI; +class JSAddonId; + +namespace mozilla { + +JSAddonId* +MapURIToAddonID(nsIURI* aURI); + +class AddonPathService final : public amIAddonPathService +{ +public: + AddonPathService(); + + static AddonPathService* GetInstance(); + + JSAddonId* Find(const nsAString& path); + static JSAddonId* FindAddonId(const nsAString& path); + + NS_DECL_ISUPPORTS + NS_DECL_AMIADDONPATHSERVICE + + struct PathEntry + { + nsString mPath; + JSAddonId* mAddonId; + + PathEntry(const nsAString& aPath, JSAddonId* aAddonId) + : mPath(aPath), mAddonId(aAddonId) + {} + }; + +private: + virtual ~AddonPathService(); + + // Paths are stored sorted in order of their mPath. + nsTArray mPaths; + + static AddonPathService* sInstance; +}; + +} // namespace mozilla + +#endif diff --git a/toolkit/mozapps/extensions/ChromeManifestParser.jsm b/toolkit/mozapps/extensions/ChromeManifestParser.jsm new file mode 100644 index 000000000..9a77c5429 --- /dev/null +++ b/toolkit/mozapps/extensions/ChromeManifestParser.jsm @@ -0,0 +1,159 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["ChromeManifestParser"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); + +const MSG_JAR_FLUSH = "AddonJarFlush"; + + +/** + * Sends local and remote notifications to flush a JAR file cache entry + * + * @param aJarFile + * The ZIP/XPI/JAR file as a nsIFile + */ +function flushJarCache(aJarFile) { + Services.obs.notifyObservers(aJarFile, "flush-cache-entry", null); + Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageBroadcaster) + .broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path); +} + + +/** + * Parses chrome manifest files. + */ +this.ChromeManifestParser = { + + /** + * Reads and parses a chrome manifest file located at a specified URI, and all + * secondary manifests it references. + * + * @param aURI + * A nsIURI pointing to a chrome manifest. + * Typically a file: or jar: URI. + * @return Array of objects describing each manifest instruction, in the form: + * { type: instruction-type, baseURI: string-uri, args: [arguments] } + **/ + parseSync: function CMP_parseSync(aURI) { + function parseLine(aLine) { + let line = aLine.trim(); + if (line.length == 0 || line.charAt(0) == '#') + return; + let tokens = line.split(/\s+/); + let type = tokens.shift(); + if (type == "manifest") { + let uri = NetUtil.newURI(tokens.shift(), null, aURI); + data = data.concat(this.parseSync(uri)); + } else { + data.push({type: type, baseURI: baseURI, args: tokens}); + } + } + + let contents = ""; + try { + if (aURI.scheme == "jar") + contents = this._readFromJar(aURI); + else + contents = this._readFromFile(aURI); + } catch (e) { + // Silently fail. + } + + if (!contents) + return []; + + let baseURI = NetUtil.newURI(".", null, aURI).spec; + + let data = []; + let lines = contents.split("\n"); + lines.forEach(parseLine.bind(this)); + return data; + }, + + _readFromJar: function CMP_readFromJar(aURI) { + let data = ""; + let entries = []; + let readers = []; + + try { + // Deconstrict URI, which can be nested jar: URIs. + let uri = aURI.clone(); + while (uri instanceof Ci.nsIJARURI) { + entries.push(uri.JAREntry); + uri = uri.JARFile; + } + + // Open the base jar. + let reader = Cc["@mozilla.org/libjar/zip-reader;1"]. + createInstance(Ci.nsIZipReader); + reader.open(uri.QueryInterface(Ci.nsIFileURL).file); + readers.push(reader); + + // Open the nested jars. + for (let i = entries.length - 1; i > 0; i--) { + let innerReader = Cc["@mozilla.org/libjar/zip-reader;1"]. + createInstance(Ci.nsIZipReader); + innerReader.openInner(reader, entries[i]); + readers.push(innerReader); + reader = innerReader; + } + + // First entry is the actual file we want to read. + let zis = reader.getInputStream(entries[0]); + data = NetUtil.readInputStreamToString(zis, zis.available()); + } + finally { + // Close readers in reverse order. + for (let i = readers.length - 1; i >= 0; i--) { + readers[i].close(); + flushJarCache(readers[i].file); + } + } + + return data; + }, + + _readFromFile: function CMP_readFromFile(aURI) { + let file = aURI.QueryInterface(Ci.nsIFileURL).file; + if (!file.exists() || !file.isFile()) + return ""; + + let data = ""; + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + try { + fis.init(file, -1, -1, false); + data = NetUtil.readInputStreamToString(fis, fis.available()); + } finally { + fis.close(); + } + return data; + }, + + /** + * Detects if there were any instructions of a specified type in a given + * chrome manifest. + * + * @param aManifest + * Manifest data, as returned by ChromeManifestParser.parseSync(). + * @param aType + * Instruction type to filter by. + * @return True if any matching instructions were found in the manifest. + */ + hasType: function CMP_hasType(aManifest, aType) { + return aManifest.some(function hasType_matchEntryType(aEntry) { + return aEntry.type == aType; + }); + } +}; diff --git a/toolkit/mozapps/extensions/DeferredSave.jsm b/toolkit/mozapps/extensions/DeferredSave.jsm new file mode 100644 index 000000000..d7f5b8864 --- /dev/null +++ b/toolkit/mozapps/extensions/DeferredSave.jsm @@ -0,0 +1,274 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +Cu.import("resource://gre/modules/osfile.jsm"); +Cu.import("resource://gre/modules/Promise.jsm"); + +// Make it possible to mock out timers for testing +let MakeTimer = () => Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + +this.EXPORTED_SYMBOLS = ["DeferredSave"]; + +// If delay parameter is not provided, default is 50 milliseconds. +const DEFAULT_SAVE_DELAY_MS = 50; + +Cu.import("resource://gre/modules/Log.jsm"); +//Configure a logger at the parent 'DeferredSave' level to format +//messages for all the modules under DeferredSave.* +const DEFERREDSAVE_PARENT_LOGGER_ID = "DeferredSave"; +let parentLogger = Log.repository.getLogger(DEFERREDSAVE_PARENT_LOGGER_ID); +parentLogger.level = Log.Level.Warn; +let formatter = new Log.BasicFormatter(); +//Set parent logger (and its children) to append to +//the Javascript section of the Browser Console +parentLogger.addAppender(new Log.ConsoleAppender(formatter)); +//Set parent logger (and its children) to +//also append to standard out +parentLogger.addAppender(new Log.DumpAppender(formatter)); + +//Provide the ability to enable/disable logging +//messages at runtime. +//If the "extensions.logging.enabled" preference is +//missing or 'false', messages at the WARNING and higher +//severity should be logged to the JS console and standard error. +//If "extensions.logging.enabled" is set to 'true', messages +//at DEBUG and higher should go to JS console and standard error. +Cu.import("resource://gre/modules/Services.jsm"); + +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; + +/** +* Preference listener which listens for a change in the +* "extensions.logging.enabled" preference and changes the logging level of the +* parent 'addons' level logger accordingly. +*/ +var PrefObserver = { + init: function PrefObserver_init() { + Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); + Services.obs.addObserver(this, "xpcom-shutdown", false); + this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); + }, + + observe: function PrefObserver_observe(aSubject, aTopic, aData) { + if (aTopic == "xpcom-shutdown") { + Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); + Services.obs.removeObserver(this, "xpcom-shutdown"); + } + else if (aTopic == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { + let debugLogEnabled = false; + try { + debugLogEnabled = Services.prefs.getBoolPref(PREF_LOGGING_ENABLED); + } + catch (e) { + } + if (debugLogEnabled) { + parentLogger.level = Log.Level.Debug; + } + else { + parentLogger.level = Log.Level.Warn; + } + } + } +}; + +PrefObserver.init(); + +/** + * A module to manage deferred, asynchronous writing of data files + * to disk. Writing is deferred by waiting for a specified delay after + * a request to save the data, before beginning to write. If more than + * one save request is received during the delay, all requests are + * fulfilled by a single write. + * + * @constructor + * @param aPath + * String representing the full path of the file where the data + * is to be written. + * @param aDataProvider + * Callback function that takes no argument and returns the data to + * be written. If aDataProvider returns an ArrayBufferView, the + * bytes it contains are written to the file as is. + * If aDataProvider returns a String the data are UTF-8 encoded + * and then written to the file. + * @param [optional] aDelay + * The delay in milliseconds between the first saveChanges() call + * that marks the data as needing to be saved, and when the DeferredSave + * begins writing the data to disk. Default 50 milliseconds. + */ +this.DeferredSave = function (aPath, aDataProvider, aDelay) { + // Create a new logger (child of 'DeferredSave' logger) + // for use by this particular instance of DeferredSave object + let leafName = OS.Path.basename(aPath); + let logger_id = DEFERREDSAVE_PARENT_LOGGER_ID + "." + leafName; + this.logger = Log.repository.getLogger(logger_id); + + // @type {Deferred|null}, null when no data needs to be written + // @resolves with the result of OS.File.writeAtomic when all writes complete + // @rejects with the error from OS.File.writeAtomic if the write fails, + // or with the error from aDataProvider() if that throws. + this._pending = null; + + // @type {Promise}, completes when the in-progress write (if any) completes, + // kept as a resolved promise at other times to simplify logic. + // Because _deferredSave() always uses _writing.then() to execute + // its next action, we don't need a special case for whether a write + // is in progress - if the previous write is complete (and the _writing + // promise is already resolved/rejected), _writing.then() starts + // the next action immediately. + // + // @resolves with the result of OS.File.writeAtomic + // @rejects with the error from OS.File.writeAtomic + this._writing = Promise.resolve(0); + + // Are we currently waiting for a write to complete + this.writeInProgress = false; + + this._path = aPath; + this._dataProvider = aDataProvider; + + this._timer = null; + + // Some counters for telemetry + // The total number of times the file was written + this.totalSaves = 0; + + // The number of times the data became dirty while + // another save was in progress + this.overlappedSaves = 0; + + // Error returned by the most recent write (if any) + this._lastError = null; + + if (aDelay && (aDelay > 0)) + this._delay = aDelay; + else + this._delay = DEFAULT_SAVE_DELAY_MS; +} + +this.DeferredSave.prototype = { + get dirty() { + return this._pending || this.writeInProgress; + }, + + get lastError() { + return this._lastError; + }, + + // Start the pending timer if data is dirty + _startTimer: function() { + if (!this._pending) { + return; + } + + this.logger.debug("Starting timer"); + if (!this._timer) + this._timer = MakeTimer(); + this._timer.initWithCallback(() => this._deferredSave(), + this._delay, Ci.nsITimer.TYPE_ONE_SHOT); + }, + + /** + * Mark the current stored data dirty, and schedule a flush to disk + * @return A Promise that will be resolved after the data is written to disk; + * the promise is resolved with the number of bytes written. + */ + saveChanges: function() { + this.logger.debug("Save changes"); + if (!this._pending) { + if (this.writeInProgress) { + this.logger.debug("Data changed while write in progress"); + this.overlappedSaves++; + } + this._pending = Promise.defer(); + // Wait until the most recent write completes or fails (if it hasn't already) + // and then restart our timer + this._writing.then(count => this._startTimer(), error => this._startTimer()); + } + return this._pending.promise; + }, + + _deferredSave: function() { + let pending = this._pending; + this._pending = null; + let writing = this._writing; + this._writing = pending.promise; + + // In either the success or the exception handling case, we don't need to handle + // the error from _writing here; it's already being handled in another then() + let toSave = null; + try { + toSave = this._dataProvider(); + } + catch(e) { + this.logger.error("Deferred save dataProvider failed", e); + writing.then(null, error => {}) + .then(count => { + pending.reject(e); + }); + return; + } + + writing.then(null, error => {return 0;}) + .then(count => { + this.logger.debug("Starting write"); + this.totalSaves++; + this.writeInProgress = true; + + OS.File.writeAtomic(this._path, toSave, {tmpPath: this._path + ".tmp"}) + .then( + result => { + this._lastError = null; + this.writeInProgress = false; + this.logger.debug("Write succeeded"); + pending.resolve(result); + }, + error => { + this._lastError = error; + this.writeInProgress = false; + this.logger.warn("Write failed", error); + pending.reject(error); + }); + }); + }, + + /** + * Immediately save the dirty data to disk, skipping + * the delay of normal operation. Note that the write + * still happens asynchronously in the worker + * thread from OS.File. + * + * There are four possible situations: + * 1) Nothing to flush + * 2) Data is not currently being written, in-memory copy is dirty + * 3) Data is currently being written, in-memory copy is clean + * 4) Data is being written and in-memory copy is dirty + * + * @return Promise that will resolve when all in-memory data + * has finished being flushed, returning the number of bytes + * written. If all in-memory data is clean, completes with the + * result of the most recent write. + */ + flush: function() { + // If we have pending changes, cancel our timer and set up the write + // immediately (_deferredSave queues the write for after the most + // recent write completes, if it hasn't already) + if (this._pending) { + this.logger.debug("Flush called while data is dirty"); + if (this._timer) { + this._timer.cancel(); + this._timer = null; + } + this._deferredSave(); + } + + return this._writing; + } +}; diff --git a/toolkit/mozapps/extensions/LightweightThemeManager.jsm b/toolkit/mozapps/extensions/LightweightThemeManager.jsm new file mode 100644 index 000000000..66761efe2 --- /dev/null +++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm @@ -0,0 +1,804 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["LightweightThemeManager"]; + +const Cc = Components.classes; +const Ci = Components.interfaces; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/AddonManager.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +const ID_SUFFIX = "@personas.mozilla.org"; +const PREF_LWTHEME_TO_SELECT = "extensions.lwThemeToSelect"; +const PREF_GENERAL_SKINS_SELECTEDSKIN = "general.skins.selectedSkin"; +const PREF_EM_DSS_ENABLED = "extensions.dss.enabled"; +const ADDON_TYPE = "theme"; + +const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties"; + +const STRING_TYPE_NAME = "type.%ID%.name"; + +const DEFAULT_MAX_USED_THEMES_COUNT = 30; + +const MAX_PREVIEW_SECONDS = 30; + +const MANDATORY = ["id", "name", "headerURL"]; +const OPTIONAL = ["footerURL", "textcolor", "accentcolor", "iconURL", + "previewURL", "author", "description", "homepageURL", + "updateURL", "version"]; + +const PERSIST_ENABLED = true; +const PERSIST_BYPASS_CACHE = false; +const PERSIST_FILES = { + headerURL: "lightweighttheme-header", + footerURL: "lightweighttheme-footer" +}; + +XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer", + "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm"); + +this.__defineGetter__("_prefs", function prefsGetter() { + delete this._prefs; + return this._prefs = Services.prefs.getBranch("lightweightThemes."); +}); + +this.__defineGetter__("_maxUsedThemes", function maxUsedThemesGetter() { + delete this._maxUsedThemes; + try { + this._maxUsedThemes = _prefs.getIntPref("maxUsedThemes"); + } + catch (e) { + this._maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT; + } + return this._maxUsedThemes; +}); + +this.__defineSetter__("_maxUsedThemes", function maxUsedThemesSetter(aVal) { + delete this._maxUsedThemes; + return this._maxUsedThemes = aVal; +}); + +// Holds the ID of the theme being enabled or disabled while sending out the +// events so cached AddonWrapper instances can return correct values for +// permissions and pendingOperations +var _themeIDBeingEnabled = null; +var _themeIDBeingDisabled = null; + +this.LightweightThemeManager = { + get name() "LightweightThemeManager", + + get usedThemes () { + try { + return JSON.parse(_prefs.getComplexValue("usedThemes", + Ci.nsISupportsString).data); + } catch (e) { + return []; + } + }, + + get currentTheme () { + try { + if (_prefs.getBoolPref("isThemeSelected")) + var data = this.usedThemes[0]; + } catch (e) {} + + return data || null; + }, + + get currentThemeForDisplay () { + var data = this.currentTheme; + + if (data && PERSIST_ENABLED) { + for (let key in PERSIST_FILES) { + try { + if (data[key] && _prefs.getBoolPref("persisted." + key)) + data[key] = _getLocalImageURI(PERSIST_FILES[key]).spec + + "?" + data.id + ";" + _version(data); + } catch (e) {} + } + } + + return data; + }, + + set currentTheme (aData) { + return _setCurrentTheme(aData, false); + }, + + setLocalTheme: function LightweightThemeManager_setLocalTheme(aData) { + _setCurrentTheme(aData, true); + }, + + getUsedTheme: function LightweightThemeManager_getUsedTheme(aId) { + var usedThemes = this.usedThemes; + for (let usedTheme of usedThemes) { + if (usedTheme.id == aId) + return usedTheme; + } + return null; + }, + + forgetUsedTheme: function LightweightThemeManager_forgetUsedTheme(aId) { + let theme = this.getUsedTheme(aId); + if (!theme) + return; + + let wrapper = new AddonWrapper(theme); + AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false); + + var currentTheme = this.currentTheme; + if (currentTheme && currentTheme.id == aId) { + this.themeChanged(null); + AddonManagerPrivate.notifyAddonChanged(null, ADDON_TYPE, false); + } + + _updateUsedThemes(_usedThemesExceptId(aId)); + AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper); + }, + + previewTheme: function LightweightThemeManager_previewTheme(aData) { + let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); + cancel.data = false; + Services.obs.notifyObservers(cancel, "lightweight-theme-preview-requested", + JSON.stringify(aData)); + if (cancel.data) + return; + + if (_previewTimer) + _previewTimer.cancel(); + else + _previewTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + _previewTimer.initWithCallback(_previewTimerCallback, + MAX_PREVIEW_SECONDS * 1000, + _previewTimer.TYPE_ONE_SHOT); + + _notifyWindows(aData); + }, + + resetPreview: function LightweightThemeManager_resetPreview() { + if (_previewTimer) { + _previewTimer.cancel(); + _previewTimer = null; + _notifyWindows(this.currentThemeForDisplay); + } + }, + + parseTheme: function LightweightThemeManager_parseTheme(aString, aBaseURI) { + try { + return _sanitizeTheme(JSON.parse(aString), aBaseURI, false); + } catch (e) { + return null; + } + }, + + updateCurrentTheme: function LightweightThemeManager_updateCurrentTheme() { + try { + if (!_prefs.getBoolPref("update.enabled")) + return; + } catch (e) { + return; + } + + var theme = this.currentTheme; + if (!theme || !theme.updateURL) + return; + + var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Ci.nsIXMLHttpRequest); + + req.mozBackgroundRequest = true; + req.overrideMimeType("text/plain"); + req.open("GET", theme.updateURL, true); + // Prevent the request from reading from the cache. + req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; + // Prevent the request from writing to the cache. + req.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; + + var self = this; + req.addEventListener("load", function loadEventListener() { + if (req.status != 200) + return; + + let newData = self.parseTheme(req.responseText, theme.updateURL); + if (!newData || + newData.id != theme.id || + _version(newData) == _version(theme)) + return; + + var currentTheme = self.currentTheme; + if (currentTheme && currentTheme.id == theme.id) + self.currentTheme = newData; + }, false); + + req.send(null); + }, + + /** + * Switches to a new lightweight theme. + * + * @param aData + * The lightweight theme to switch to + */ + themeChanged: function LightweightThemeManager_themeChanged(aData) { + if (_previewTimer) { + _previewTimer.cancel(); + _previewTimer = null; + } + + if (aData) { + let usedThemes = _usedThemesExceptId(aData.id); + usedThemes.unshift(aData); + _updateUsedThemes(usedThemes); + if (PERSIST_ENABLED) { + LightweightThemeImageOptimizer.purge(); + _persistImages(aData, function themeChanged_persistImages() { + _notifyWindows(this.currentThemeForDisplay); + }.bind(this)); + } + } + + _prefs.setBoolPref("isThemeSelected", aData != null); + _notifyWindows(aData); + Services.obs.notifyObservers(null, "lightweight-theme-changed", null); + }, + + /** + * Starts the Addons provider and enables the new lightweight theme if + * necessary. + */ + startup: function LightweightThemeManager_startup() { + if (Services.prefs.prefHasUserValue(PREF_LWTHEME_TO_SELECT)) { + let id = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); + if (id) + this.themeChanged(this.getUsedTheme(id)); + else + this.themeChanged(null); + Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT); + } + + _prefs.addObserver("", _prefObserver, false); + }, + + /** + * Shuts down the provider. + */ + shutdown: function LightweightThemeManager_shutdown() { + _prefs.removeObserver("", _prefObserver); + }, + + /** + * Called when a new add-on has been enabled when only one add-on of that type + * can be enabled. + * + * @param aId + * The ID of the newly enabled add-on + * @param aType + * The type of the newly enabled add-on + * @param aPendingRestart + * true if the newly enabled add-on will only become enabled after a + * restart + */ + addonChanged: function LightweightThemeManager_addonChanged(aId, aType, aPendingRestart) { + if (aType != ADDON_TYPE) + return; + + let id = _getInternalID(aId); + let current = this.currentTheme; + + try { + let next = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); + if (id == next && aPendingRestart) + return; + + Services.prefs.clearUserPref(PREF_LWTHEME_TO_SELECT); + if (next) { + AddonManagerPrivate.callAddonListeners("onOperationCancelled", + new AddonWrapper(this.getUsedTheme(next))); + } + else { + if (id == current.id) { + AddonManagerPrivate.callAddonListeners("onOperationCancelled", + new AddonWrapper(current)); + return; + } + } + } + catch (e) { + } + + if (current) { + if (current.id == id) + return; + _themeIDBeingDisabled = current.id; + let wrapper = new AddonWrapper(current); + if (aPendingRestart) { + Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, ""); + AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, true); + } + else { + AddonManagerPrivate.callAddonListeners("onDisabling", wrapper, false); + this.themeChanged(null); + AddonManagerPrivate.callAddonListeners("onDisabled", wrapper); + } + _themeIDBeingDisabled = null; + } + + if (id) { + let theme = this.getUsedTheme(id); + _themeIDBeingEnabled = id; + let wrapper = new AddonWrapper(theme); + if (aPendingRestart) { + AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, true); + Services.prefs.setCharPref(PREF_LWTHEME_TO_SELECT, id); + + // Flush the preferences to disk so they survive any crash + Services.prefs.savePrefFile(null); + } + else { + AddonManagerPrivate.callAddonListeners("onEnabling", wrapper, false); + this.themeChanged(theme); + AddonManagerPrivate.callAddonListeners("onEnabled", wrapper); + } + _themeIDBeingEnabled = null; + } + }, + + /** + * Called to get an Addon with a particular ID. + * + * @param aId + * The ID of the add-on to retrieve + * @param aCallback + * A callback to pass the Addon to + */ + getAddonByID: function LightweightThemeManager_getAddonByID(aId, aCallback) { + let id = _getInternalID(aId); + if (!id) { + aCallback(null); + return; + } + + let theme = this.getUsedTheme(id); + if (!theme) { + aCallback(null); + return; + } + + aCallback(new AddonWrapper(theme)); + }, + + /** + * Called to get Addons of a particular type. + * + * @param aTypes + * An array of types to fetch. Can be null to get all types. + * @param aCallback + * A callback to pass an array of Addons to + */ + getAddonsByTypes: function LightweightThemeManager_getAddonsByTypes(aTypes, aCallback) { + if (aTypes && aTypes.indexOf(ADDON_TYPE) == -1) { + aCallback([]); + return; + } + + aCallback([new AddonWrapper(a) for each (a in this.usedThemes)]); + }, +}; + +/** + * The AddonWrapper wraps lightweight theme to provide the data visible to + * consumers of the AddonManager API. + */ +function AddonWrapper(aTheme) { + this.__defineGetter__("id", function AddonWrapper_idGetter() aTheme.id + ID_SUFFIX); + this.__defineGetter__("type", function AddonWrapper_typeGetter() ADDON_TYPE); + this.__defineGetter__("isActive", function AddonWrapper_isActiveGetter() { + let current = LightweightThemeManager.currentTheme; + if (current) + return aTheme.id == current.id; + return false; + }); + + this.__defineGetter__("name", function AddonWrapper_nameGetter() aTheme.name); + this.__defineGetter__("version", function AddonWrapper_versionGetter() { + return "version" in aTheme ? aTheme.version : ""; + }); + + ["description", "homepageURL", "iconURL"].forEach(function(prop) { + this.__defineGetter__(prop, function AddonWrapper_optionalPropGetter() { + return prop in aTheme ? aTheme[prop] : null; + }); + }, this); + + ["installDate", "updateDate"].forEach(function(prop) { + this.__defineGetter__(prop, function AddonWrapper_datePropGetter() { + return prop in aTheme ? new Date(aTheme[prop]) : null; + }); + }, this); + + this.__defineGetter__("creator", function AddonWrapper_creatorGetter() { + return new AddonManagerPrivate.AddonAuthor(aTheme.author); + }); + + this.__defineGetter__("screenshots", function AddonWrapper_screenshotsGetter() { + let url = aTheme.previewURL; + return [new AddonManagerPrivate.AddonScreenshot(url)]; + }); + + this.__defineGetter__("pendingOperations", + function AddonWrapper_pendingOperationsGetter() { + let pending = AddonManager.PENDING_NONE; + if (this.isActive == this.userDisabled) + pending |= this.isActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE; + return pending; + }); + + this.__defineGetter__("operationsRequiringRestart", + function AddonWrapper_operationsRequiringRestartGetter() { + // If a non-default theme is in use then a restart will be required to + // enable lightweight themes unless dynamic theme switching is enabled + if (Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN)) { + try { + if (Services.prefs.getBoolPref(PREF_EM_DSS_ENABLED)) + return AddonManager.OP_NEEDS_RESTART_NONE; + } + catch (e) { + } + return AddonManager.OP_NEEDS_RESTART_ENABLE; + } + + return AddonManager.OP_NEEDS_RESTART_NONE; + }); + + this.__defineGetter__("size", function AddonWrapper_sizeGetter() { + // The size changes depending on whether the theme is in use or not, this is + // probably not worth exposing. + return null; + }); + + this.__defineGetter__("permissions", function AddonWrapper_permissionsGetter() { + let permissions = AddonManager.PERM_CAN_UNINSTALL; + if (this.userDisabled) + permissions |= AddonManager.PERM_CAN_ENABLE; + else + permissions |= AddonManager.PERM_CAN_DISABLE; + return permissions; + }); + + this.__defineGetter__("userDisabled", function AddonWrapper_userDisabledGetter() { + if (_themeIDBeingEnabled == aTheme.id) + return false; + if (_themeIDBeingDisabled == aTheme.id) + return true; + + try { + let toSelect = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT); + return aTheme.id != toSelect; + } + catch (e) { + let current = LightweightThemeManager.currentTheme; + return !current || current.id != aTheme.id; + } + }); + + this.__defineSetter__("userDisabled", function AddonWrapper_userDisabledSetter(val) { + if (val == this.userDisabled) + return val; + + if (val) + LightweightThemeManager.currentTheme = null; + else + LightweightThemeManager.currentTheme = aTheme; + + return val; + }); + + this.uninstall = function AddonWrapper_uninstall() { + LightweightThemeManager.forgetUsedTheme(aTheme.id); + }; + + this.cancelUninstall = function AddonWrapper_cancelUninstall() { + throw new Error("Theme is not marked to be uninstalled"); + }; + + this.findUpdates = function AddonWrapper_findUpdates(listener, reason, appVersion, platformVersion) { + AddonManagerPrivate.callNoUpdateListeners(this, listener, reason, appVersion, platformVersion); + }; +} + +AddonWrapper.prototype = { + // Lightweight themes are never disabled by the application + get appDisabled() { + return false; + }, + + // Lightweight themes are always compatible + get isCompatible() { + return true; + }, + + get isPlatformCompatible() { + return true; + }, + + get scope() { + return AddonManager.SCOPE_PROFILE; + }, + + get foreignInstall() { + return false; + }, + + // Lightweight themes are always compatible + isCompatibleWith: function AddonWrapper_isCompatibleWith(appVersion, platformVersion) { + return true; + }, + + // Lightweight themes are always securely updated + get providesUpdatesSecurely() { + return true; + }, + + // Lightweight themes are never blocklisted + get blocklistState() { + return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + } +}; + +/** + * Converts the ID used by the public AddonManager API to an lightweight theme + * ID. + * + * @param id + * The ID to be converted + * + * @return the lightweight theme ID or null if the ID was not for a lightweight + * theme. + */ +function _getInternalID(id) { + if (!id) + return null; + let len = id.length - ID_SUFFIX.length; + if (len > 0 && id.substring(len) == ID_SUFFIX) + return id.substring(0, len); + return null; +} + +function _setCurrentTheme(aData, aLocal) { + aData = _sanitizeTheme(aData, null, aLocal); + + let needsRestart = (ADDON_TYPE == "theme") && + Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN); + + let cancel = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); + cancel.data = false; + Services.obs.notifyObservers(cancel, "lightweight-theme-change-requested", + JSON.stringify(aData)); + + if (aData) { + let theme = LightweightThemeManager.getUsedTheme(aData.id); + let isInstall = !theme || theme.version != aData.version; + if (isInstall) { + aData.updateDate = Date.now(); + if (theme && "installDate" in theme) + aData.installDate = theme.installDate; + else + aData.installDate = aData.updateDate; + + var oldWrapper = theme ? new AddonWrapper(theme) : null; + var wrapper = new AddonWrapper(aData); + AddonManagerPrivate.callInstallListeners("onExternalInstall", null, + wrapper, oldWrapper, false); + AddonManagerPrivate.callAddonListeners("onInstalling", wrapper, false); + } + + let current = LightweightThemeManager.currentTheme; + let usedThemes = _usedThemesExceptId(aData.id); + if (current && current.id != aData.id) + usedThemes.splice(1, 0, aData); + else + usedThemes.unshift(aData); + _updateUsedThemes(usedThemes); + + if (isInstall) + AddonManagerPrivate.callAddonListeners("onInstalled", wrapper); + } + + if (cancel.data) + return null; + + AddonManagerPrivate.notifyAddonChanged(aData ? aData.id + ID_SUFFIX : null, + ADDON_TYPE, needsRestart); + + return LightweightThemeManager.currentTheme; +} + +function _sanitizeTheme(aData, aBaseURI, aLocal) { + if (!aData || typeof aData != "object") + return null; + + var resourceProtocols = ["http", "https", "resource"]; + if (aLocal) + resourceProtocols.push("file"); + var resourceProtocolExp = new RegExp("^(" + resourceProtocols.join("|") + "):"); + + function sanitizeProperty(prop) { + if (!(prop in aData)) + return null; + if (typeof aData[prop] != "string") + return null; + let val = aData[prop].trim(); + if (!val) + return null; + + if (!/URL$/.test(prop)) + return val; + + try { + val = _makeURI(val, aBaseURI ? _makeURI(aBaseURI) : null).spec; + if ((prop == "updateURL" ? /^https:/ : resourceProtocolExp).test(val)) + return val; + return null; + } + catch (e) { + return null; + } + } + + let result = {}; + for (let mandatoryProperty of MANDATORY) { + let val = sanitizeProperty(mandatoryProperty); + if (!val) + throw Components.results.NS_ERROR_INVALID_ARG; + result[mandatoryProperty] = val; + } + + for (let optionalProperty of OPTIONAL) { + let val = sanitizeProperty(optionalProperty); + if (!val) + continue; + result[optionalProperty] = val; + } + + return result; +} + +function _usedThemesExceptId(aId) + LightweightThemeManager.usedThemes.filter( + function usedThemesExceptId_filterID(t) "id" in t && t.id != aId); + +function _version(aThemeData) + aThemeData.version || ""; + +function _makeURI(aURL, aBaseURI) + Services.io.newURI(aURL, null, aBaseURI); + +function _updateUsedThemes(aList) { + // Send uninstall events for all themes that need to be removed. + while (aList.length > _maxUsedThemes) { + let wrapper = new AddonWrapper(aList[aList.length - 1]); + AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false); + aList.pop(); + AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper); + } + + var str = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + str.data = JSON.stringify(aList); + _prefs.setComplexValue("usedThemes", Ci.nsISupportsString, str); + + Services.obs.notifyObservers(null, "lightweight-theme-list-changed", null); +} + +function _notifyWindows(aThemeData) { + Services.obs.notifyObservers(null, "lightweight-theme-styling-update", + JSON.stringify(aThemeData)); +} + +var _previewTimer; +var _previewTimerCallback = { + notify: function _previewTimerCallback_notify() { + LightweightThemeManager.resetPreview(); + } +}; + +/** + * Called when any of the lightweightThemes preferences are changed. + */ +function _prefObserver(aSubject, aTopic, aData) { + switch (aData) { + case "maxUsedThemes": + try { + _maxUsedThemes = _prefs.getIntPref(aData); + } + catch (e) { + _maxUsedThemes = DEFAULT_MAX_USED_THEMES_COUNT; + } + // Update the theme list to remove any themes over the number we keep + _updateUsedThemes(LightweightThemeManager.usedThemes); + break; + } +} + +function _persistImages(aData, aCallback) { + function onSuccess(key) function () { + let current = LightweightThemeManager.currentTheme; + if (current && current.id == aData.id) { + _prefs.setBoolPref("persisted." + key, true); + } + if (--numFilesToPersist == 0 && aCallback) { + aCallback(); + } + }; + + let numFilesToPersist = 0; + for (let key in PERSIST_FILES) { + _prefs.setBoolPref("persisted." + key, false); + if (aData[key]) { + numFilesToPersist++; + _persistImage(aData[key], PERSIST_FILES[key], onSuccess(key)); + } + } +} + +function _getLocalImageURI(localFileName) { + var localFile = Services.dirsvc.get("ProfD", Ci.nsIFile); + localFile.append(localFileName); + return Services.io.newFileURI(localFile); +} + +function _persistImage(sourceURL, localFileName, successCallback) { + if (/^(file|resource):/.test(sourceURL)) + return; + + var targetURI = _getLocalImageURI(localFileName); + var sourceURI = _makeURI(sourceURL); + + var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"] + .createInstance(Ci.nsIWebBrowserPersist); + + persist.persistFlags = + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES | + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION | + (PERSIST_BYPASS_CACHE ? + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_BYPASS_CACHE : + Ci.nsIWebBrowserPersist.PERSIST_FLAGS_FROM_CACHE); + + persist.progressListener = new _persistProgressListener(successCallback); + + persist.saveURI(sourceURI, null, + null, Ci.nsIHttpChannel.REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE, + null, null, targetURI, null); +} + +function _persistProgressListener(successCallback) { + this.onLocationChange = function persistProgressListener_onLocationChange() {}; + this.onProgressChange = function persistProgressListener_onProgressChange() {}; + this.onStatusChange = function persistProgressListener_onStatusChange() {}; + this.onSecurityChange = function persistProgressListener_onSecurityChange() {}; + this.onStateChange = function persistProgressListener_onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) { + if (aRequest && + aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK && + aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) { + try { + if (aRequest.QueryInterface(Ci.nsIHttpChannel).requestSucceeded) { + // success + successCallback(); + return; + } + } catch (e) { } + // failure + } + }; +} + +AddonManagerPrivate.registerProvider(LightweightThemeManager, [ + new AddonManagerPrivate.AddonType("theme", URI_EXTENSION_STRINGS, + STRING_TYPE_NAME, + AddonManager.VIEW_TYPE_LIST, 5000) +]); diff --git a/toolkit/mozapps/extensions/addonManager.js b/toolkit/mozapps/extensions/addonManager.js new file mode 100644 index 000000000..862b1ea69 --- /dev/null +++ b/toolkit/mozapps/extensions/addonManager.js @@ -0,0 +1,204 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This component serves as integration between the platform and AddonManager. + * It is responsible for initializing and shutting down the AddonManager as well + * as passing new installs from webpages to the AddonManager. + */ + +"use strict"; + +const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; + +const PREF_EM_UPDATE_INTERVAL = "extensions.update.interval"; + +// The old XPInstall error codes +const EXECUTION_ERROR = -203; +const CANT_READ_ARCHIVE = -207; +const USER_CANCELLED = -210; +const DOWNLOAD_ERROR = -228; +const UNSUPPORTED_TYPE = -244; +const SUCCESS = 0; + +const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; +const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; +const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; + +const CHILD_SCRIPT = "resource://gre/modules/addons/Content.js"; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +let gSingleton = null; + +let gParentMM = null; + + +function amManager() { + Cu.import("resource://gre/modules/AddonManager.jsm"); + + let globalMM = Cc["@mozilla.org/globalmessagemanager;1"] + .getService(Ci.nsIMessageListenerManager); + globalMM.loadFrameScript(CHILD_SCRIPT, true); + globalMM.addMessageListener(MSG_INSTALL_ADDONS, this); + + gParentMM = Cc["@mozilla.org/parentprocessmessagemanager;1"] + .getService(Ci.nsIMessageListenerManager); + gParentMM.addMessageListener(MSG_INSTALL_ENABLED, this); + + // Needed so receiveMessage can be called directly by JS callers + this.wrappedJSObject = this; +} + +amManager.prototype = { + observe: function AMC_observe(aSubject, aTopic, aData) { + if (aTopic == "addons-startup") + AddonManagerPrivate.startup(); + }, + + /** + * @see amIAddonManager.idl + */ + mapURIToAddonID: function AMC_mapURIToAddonID(uri, id) { + id.value = AddonManager.mapURIToAddonID(uri); + return !!id.value; + }, + + /** + * @see amIWebInstaller.idl + */ + isInstallEnabled: function AMC_isInstallEnabled(aMimetype, aReferer) { + return AddonManager.isInstallEnabled(aMimetype); + }, + + /** + * @see amIWebInstaller.idl + */ + installAddonsFromWebpage: function AMC_installAddonsFromWebpage(aMimetype, + aBrowser, + aInstallingPrincipal, + aUris, aHashes, + aNames, aIcons, + aCallback) { + if (aUris.length == 0) + return false; + + let retval = true; + if (!AddonManager.isInstallAllowed(aMimetype, aInstallingPrincipal)) { + aCallback = null; + retval = false; + } + + let installs = []; + function buildNextInstall() { + if (aUris.length == 0) { + AddonManager.installAddonsFromWebpage(aMimetype, aBrowser, aInstallingPrincipal, installs); + return; + } + let uri = aUris.shift(); + AddonManager.getInstallForURL(uri, function buildNextInstall_getInstallForURL(aInstall) { + function callCallback(aUri, aStatus) { + try { + aCallback.onInstallEnded(aUri, aStatus); + } + catch (e) { + Components.utils.reportError(e); + } + } + + if (aInstall) { + installs.push(aInstall); + if (aCallback) { + aInstall.addListener({ + onDownloadCancelled: function buildNextInstall_onDownloadCancelled(aInstall) { + callCallback(uri, USER_CANCELLED); + }, + + onDownloadFailed: function buildNextInstall_onDownloadFailed(aInstall) { + if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE) + callCallback(uri, CANT_READ_ARCHIVE); + else + callCallback(uri, DOWNLOAD_ERROR); + }, + + onInstallFailed: function buildNextInstall_onInstallFailed(aInstall) { + callCallback(uri, EXECUTION_ERROR); + }, + + onInstallEnded: function buildNextInstall_onInstallEnded(aInstall, aStatus) { + callCallback(uri, SUCCESS); + } + }); + } + } + else if (aCallback) { + aCallback.onInstallEnded(uri, UNSUPPORTED_TYPE); + } + buildNextInstall(); + }, aMimetype, aHashes.shift(), aNames.shift(), aIcons.shift(), null, aBrowser); + } + buildNextInstall(); + + return retval; + }, + + notify: function AMC_notify(aTimer) { + AddonManagerPrivate.backgroundUpdateTimerHandler(); + }, + + /** + * messageManager callback function. + * + * Listens to requests from child processes for InstallTrigger + * activity, and sends back callbacks. + */ + receiveMessage: function AMC_receiveMessage(aMessage) { + let payload = aMessage.data; + + switch (aMessage.name) { + case MSG_INSTALL_ENABLED: + return AddonManager.isInstallEnabled(payload.mimetype); + + case MSG_INSTALL_ADDONS: { + let callback = null; + if (payload.callbackID != -1) { + callback = { + onInstallEnded: function ITP_callback(url, status) { + gParentMM.broadcastAsyncMessage(MSG_INSTALL_CALLBACK, { + callbackID: payload.callbackID, + url: url, + status: status + }); + }, + }; + } + + return this.installAddonsFromWebpage(payload.mimetype, + aMessage.target, payload.triggeringPrincipal, payload.uris, + payload.hashes, payload.names, payload.icons, callback); + } + } + }, + + classID: Components.ID("{4399533d-08d1-458c-a87a-235f74451cfa}"), + _xpcom_factory: { + createInstance: function AMC_createInstance(aOuter, aIid) { + if (aOuter != null) + throw Components.Exception("Component does not support aggregation", + Cr.NS_ERROR_NO_AGGREGATION); + + if (!gSingleton) + gSingleton = new amManager(); + return gSingleton.QueryInterface(aIid); + } + }, + QueryInterface: XPCOMUtils.generateQI([Ci.amIAddonManager, + Ci.amIWebInstaller, + Ci.nsITimerCallback, + Ci.nsIObserver, + Ci.nsIMessageListener]) +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amManager]); diff --git a/toolkit/mozapps/extensions/amContentHandler.js b/toolkit/mozapps/extensions/amContentHandler.js new file mode 100644 index 000000000..708f670b1 --- /dev/null +++ b/toolkit/mozapps/extensions/amContentHandler.js @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; + +const XPI_CONTENT_TYPE = "application/x-xpinstall"; +const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); + +function amContentHandler() { +} + +amContentHandler.prototype = { + /** + * Handles a new request for an application/x-xpinstall file. + * + * @param aMimetype + * The mimetype of the file + * @param aContext + * The context passed to nsIChannel.asyncOpen + * @param aRequest + * The nsIRequest dealing with the content + */ + handleContent: function XCH_handleContent(aMimetype, aContext, aRequest) { + if (aMimetype != XPI_CONTENT_TYPE) + throw Cr.NS_ERROR_WONT_HANDLE_CONTENT; + + if (!(aRequest instanceof Ci.nsIChannel)) + throw Cr.NS_ERROR_WONT_HANDLE_CONTENT; + + let uri = aRequest.URI; + + let window = null; + let callbacks = aRequest.notificationCallbacks ? + aRequest.notificationCallbacks : + aRequest.loadGroup.notificationCallbacks; + if (callbacks) + window = callbacks.getInterface(Ci.nsIDOMWindow); + + aRequest.cancel(Cr.NS_BINDING_ABORTED); + + let installs = { + uris: [uri.spec], + hashes: [null], + names: [null], + icons: [null], + mimetype: XPI_CONTENT_TYPE, + triggeringPrincipal: aRequest.loadInfo.triggeringPrincipal, + callbackID: -1 + }; + + if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + // When running in the main process this might be a frame inside an + // in-content UI page, walk up to find the first frame element in a chrome + // privileged document + let element = window.frameElement; + let ssm = Services.scriptSecurityManager; + while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) + element = element.ownerDocument.defaultView.frameElement; + + if (element) { + let listener = Cc["@mozilla.org/addons/integration;1"]. + getService(Ci.nsIMessageListener); + listener.wrappedJSObject.receiveMessage({ + name: MSG_INSTALL_ADDONS, + target: element, + data: installs, + }); + return; + } + } + + // Fall back to sending through the message manager + let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + + messageManager.sendAsyncMessage(MSG_INSTALL_ADDONS, installs); + }, + + classID: Components.ID("{7beb3ba8-6ec3-41b4-b67c-da89b8518922}"), + QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentHandler]), + + log : function XCH_log(aMsg) { + let msg = "amContentHandler.js: " + (aMsg.join ? aMsg.join("") : aMsg); + Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService). + logStringMessage(msg); + dump(msg + "\n"); + } +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([amContentHandler]); diff --git a/toolkit/mozapps/extensions/amIAddonManager.idl b/toolkit/mozapps/extensions/amIAddonManager.idl new file mode 100644 index 000000000..58a58b62d --- /dev/null +++ b/toolkit/mozapps/extensions/amIAddonManager.idl @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIURI; + +/** + * A service to make some AddonManager functionality available to C++ callers. + * Javascript callers should still use AddonManager.jsm directly. + */ +[scriptable, function, uuid(7b45d82d-7ad5-48d7-9b05-f32eb9818cd4)] +interface amIAddonManager : nsISupports +{ + /** + * Synchronously map a URI to the corresponding Addon ID. + * + * Mappable URIs are limited to in-application resources belonging to the + * add-on, such as Javascript compartments, XUL windows, XBL bindings, etc. + * but do not include URIs from meta data, such as the add-on homepage. + * + * @param aURI + * The nsIURI to map + * @return + * true if the URI has been mapped successfully to an Addon ID + */ + boolean mapURIToAddonID(in nsIURI aURI, out AUTF8String aID); +}; diff --git a/toolkit/mozapps/extensions/amIAddonPathService.idl b/toolkit/mozapps/extensions/amIAddonPathService.idl new file mode 100644 index 000000000..863689858 --- /dev/null +++ b/toolkit/mozapps/extensions/amIAddonPathService.idl @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +/** + * This service maps file system paths where add-ons reside to the ID + * of the add-on. Paths are added by the add-on manager. They can + * looked up by anyone. + */ +[scriptable, uuid(fcd9e270-dfb1-11e3-8b68-0800200c9a66)] +interface amIAddonPathService : nsISupports +{ + /** + * Given a path to a file, return the ID of the add-on that the file belongs + * to. Returns an empty string if there is no add-on there. Note that if an + * add-on is located at /a/b/c, then looking up the path /a/b/c/d will return + * that add-on. + */ + AString findAddonId(in AString path); + + /** + * Call this function to inform the service that the given file system path is + * associated with the given add-on ID. + */ + void insertPath(in AString path, in AString addonId); +}; diff --git a/toolkit/mozapps/extensions/amIWebInstallListener.idl b/toolkit/mozapps/extensions/amIWebInstallListener.idl new file mode 100644 index 000000000..eed108097 --- /dev/null +++ b/toolkit/mozapps/extensions/amIWebInstallListener.idl @@ -0,0 +1,134 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMElement; +interface nsIURI; +interface nsIVariant; + +/** + * amIWebInstallInfo is used by the default implementation of + * amIWebInstallListener to communicate with the running application and allow + * it to warn the user about blocked installs and start the installs running. + */ +[scriptable, uuid(fa0b47a3-f819-47ac-bc66-4bd1d7f67b1d)] +interface amIWebInstallInfo : nsISupports +{ + readonly attribute nsIDOMElement browser; + readonly attribute nsIURI originatingURI; + readonly attribute nsIVariant installs; + + /** + * Starts all installs. + */ + void install(); +}; + +/** + * The registered amIWebInstallListener is used to notify about new installs + * triggered by websites. The default implementation displays a confirmation + * dialog when add-ons are ready to install and uses the observer service to + * notify when installations are blocked. + */ +[scriptable, uuid(d9240d4b-6b3a-4cad-b402-de6c93337e0c)] +interface amIWebInstallListener : nsISupports +{ + /** + * Called when installation by websites is currently disabled. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were blocked + * @param aCount + * The number of AddonInstalls + */ + void onWebInstallDisabled(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); + + /** + * Called when the website is not allowed to directly prompt the user to + * install add-ons. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were blocked + * @param aCount + * The number of AddonInstalls + * @return true if the caller should start the installs + */ + boolean onWebInstallBlocked(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); + + /** + * Called when a website wants to ask the user to install add-ons. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were requested + * @param aCount + * The number of AddonInstalls + * @return true if the caller should start the installs + */ + boolean onWebInstallRequested(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); +}; + +[scriptable, uuid(a80b89ad-bb1a-4c43-9cb7-3ae656556f78)] +interface amIWebInstallListener2 : nsISupports +{ + /** + * Called when a non-same-origin resource attempted to initiate an install. + * Installs will have already been cancelled and cannot be restarted. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were blocked + * @param aCount + * The number of AddonInstalls + */ + boolean onWebInstallOriginBlocked(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); +}; + +/** + * amIWebInstallPrompt is used, if available, by the default implementation of + * amIWebInstallInfo to display a confirmation UI to the user before running + * installs. + */ +[scriptable, uuid(386906f1-4d18-45bf-bc81-5dcd68e42c3b)] +interface amIWebInstallPrompt : nsISupports +{ + /** + * Get a confirmation that the user wants to start the installs. + * + * @param aBrowser + * The browser that triggered the installs + * @param aUri + * The URI of the site that triggered the installs + * @param aInstalls + * The AddonInstalls that were requested + * @param aCount + * The number of AddonInstalls + */ + void confirm(in nsIDOMElement aBrowser, in nsIURI aUri, + [array, size_is(aCount)] in nsIVariant aInstalls, + [optional] in uint32_t aCount); +}; diff --git a/toolkit/mozapps/extensions/amIWebInstaller.idl b/toolkit/mozapps/extensions/amIWebInstaller.idl new file mode 100644 index 000000000..6c5ebca67 --- /dev/null +++ b/toolkit/mozapps/extensions/amIWebInstaller.idl @@ -0,0 +1,82 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMElement; +interface nsIVariant; +interface nsIURI; + +/** + * A callback function used to notify webpages when a requested install has + * ended. + * + * NOTE: This is *not* the same as InstallListener. + */ +[scriptable, function, uuid(bb22f5c0-3ca1-48f6-873c-54e87987700f)] +interface amIInstallCallback : nsISupports +{ + /** + * Called when an install completes or fails. + * + * @param aUrl + * The url of the add-on being installed + * @param aStatus + * 0 if the install was successful or negative if not + */ + void onInstallEnded(in AString aUrl, in int32_t aStatus); +}; + + +/** + * This interface is used to allow webpages to start installing add-ons. + */ +[scriptable, uuid(658d6c09-15e0-4688-bee8-8551030472a9)] +interface amIWebInstaller : nsISupports +{ + /** + * Checks if installation is enabled for a webpage. + * + * @param aMimetype + * The mimetype for the add-on to be installed + * @param referer + * The URL of the webpage trying to install an add-on + * @return true if installation is enabled + */ + boolean isInstallEnabled(in AString aMimetype, in nsIURI aReferer); + + /** + * Installs an array of add-ons at the request of a webpage + * + * @param aMimetype + * The mimetype for the add-ons + * @param aBrowser + * The browser installing the add-ons. + * @param aReferer + * The URI for the webpage installing the add-ons + * @param aUris + * The URIs of add-ons to be installed + * @param aHashes + * The hashes for the add-ons to be installed + * @param aNames + * The names for the add-ons to be installed + * @param aIcons + * The icons for the add-ons to be installed + * @param aCallback + * An optional callback to notify about installation success and + * failure + * @param aInstallCount + * An optional argument including the number of add-ons to install + * @return true if the installation was successfully started + */ + boolean installAddonsFromWebpage(in AString aMimetype, + in nsIDOMElement aBrowser, + in nsIURI aReferer, + [array, size_is(aInstallCount)] in wstring aUris, + [array, size_is(aInstallCount)] in wstring aHashes, + [array, size_is(aInstallCount)] in wstring aNames, + [array, size_is(aInstallCount)] in wstring aIcons, + [optional] in amIInstallCallback aCallback, + [optional] in uint32_t aInstallCount); +}; diff --git a/toolkit/mozapps/extensions/amInstallTrigger.js b/toolkit/mozapps/extensions/amInstallTrigger.js new file mode 100644 index 000000000..b83cbe60b --- /dev/null +++ b/toolkit/mozapps/extensions/amInstallTrigger.js @@ -0,0 +1,230 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Preferences.jsm"); +Cu.import("resource://gre/modules/Log.jsm"); + +const XPINSTALL_MIMETYPE = "application/x-xpinstall"; + +const MSG_INSTALL_ENABLED = "WebInstallerIsInstallEnabled"; +const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage"; +const MSG_INSTALL_CALLBACK = "WebInstallerInstallCallback"; + + +let log = Log.repository.getLogger("AddonManager.InstallTrigger"); +log.level = Log.Level[Preferences.get("extensions.logging.enabled", false) ? "Warn" : "Trace"]; + +function CallbackObject(id, callback, urls, mediator) { + this.id = id; + this.callback = callback; + this.urls = new Set(urls); + this.callCallback = function(url, status) { + try { + this.callback(url, status); + } + catch (e) { + log.warn("InstallTrigger callback threw an exception: " + e); + } + + this.urls.delete(url); + if (this.urls.size == 0) + mediator._callbacks.delete(id); + }; +} + +function RemoteMediator(windowID) { + this._windowID = windowID; + this._lastCallbackID = 0; + this._callbacks = new Map(); + this.mm = Cc["@mozilla.org/childprocessmessagemanager;1"] + .getService(Ci.nsISyncMessageSender); + this.mm.addWeakMessageListener(MSG_INSTALL_CALLBACK, this); +} + +RemoteMediator.prototype = { + receiveMessage: function(message) { + if (message.name == MSG_INSTALL_CALLBACK) { + let payload = message.data; + let callbackHandler = this._callbacks.get(payload.callbackID); + if (callbackHandler) { + callbackHandler.callCallback(payload.url, payload.status); + } + } + }, + + enabled: function(url) { + let params = { + mimetype: XPINSTALL_MIMETYPE + }; + return this.mm.sendSyncMessage(MSG_INSTALL_ENABLED, params)[0]; + }, + + install: function(installs, principal, callback, window) { + let callbackID = this._addCallback(callback, installs.uris); + + installs.mimetype = XPINSTALL_MIMETYPE; + installs.triggeringPrincipal = principal; + installs.callbackID = callbackID; + + if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { + // When running in the main process this might be a frame inside an + // in-content UI page, walk up to find the first frame element in a chrome + // privileged document + let element = window.frameElement; + let ssm = Services.scriptSecurityManager; + while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal)) + element = element.ownerDocument.defaultView.frameElement; + + if (element) { + let listener = Cc["@mozilla.org/addons/integration;1"]. + getService(Ci.nsIMessageListener); + return listener.wrappedJSObject.receiveMessage({ + name: MSG_INSTALL_ADDONS, + target: element, + data: installs, + }); + } + } + + // Fall back to sending through the message manager + let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell) + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIContentFrameMessageManager); + + return messageManager.sendSyncMessage(MSG_INSTALL_ADDONS, installs)[0]; + }, + + _addCallback: function(callback, urls) { + if (!callback || typeof callback != "function") + return -1; + + let callbackID = this._windowID + "-" + ++this._lastCallbackID; + let callbackObject = new CallbackObject(callbackID, callback, urls, this); + this._callbacks.set(callbackID, callbackObject); + return callbackID; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference]) +}; + + +function InstallTrigger() { +} + +InstallTrigger.prototype = { + // Here be magic. We've declared ourselves as providing the + // nsIDOMGlobalPropertyInitializer interface, and are registered in the + // "JavaScript-global-property" category in the XPCOM category manager. This + // means that for newly created windows, XPCOM will createinstance this + // object, and then call init, passing in the window for which we need to + // provide an instance. We then initialize ourselves and return the webidl + // version of this object using the webidl-provided _create method, which + // XPCOM will then duly expose as a property value on the window. All this + // indirection is necessary because webidl does not (yet) support statics + // (bug 863952). See bug 926712 for more details about this implementation. + init: function(window) { + this._window = window; + this._principal = window.document.nodePrincipal; + this._url = window.document.documentURIObject; + + window.QueryInterface(Components.interfaces.nsIInterfaceRequestor); + let utils = window.getInterface(Components.interfaces.nsIDOMWindowUtils); + this._mediator = new RemoteMediator(utils.currentInnerWindowID); + + return window.InstallTriggerImpl._create(window, this); + }, + + enabled: function() { + return this._mediator.enabled(this._url.spec); + }, + + updateEnabled: function() { + return this.enabled(); + }, + + install: function(installs, callback) { + let installData = { + uris: [], + hashes: [], + names: [], + icons: [], + }; + + for (let name of Object.keys(installs)) { + let item = installs[name]; + if (typeof item === "string") { + item = { URL: item }; + } + if (!item.URL) { + throw new this._window.DOMError("Error", "Missing URL property for '" + name + "'"); + } + + let url = this._resolveURL(item.URL); + if (!this._checkLoadURIFromScript(url)) { + throw new this._window.DOMError("SecurityError", "Insufficient permissions to install: " + url.spec); + } + + let iconUrl = null; + if (item.IconURL) { + iconUrl = this._resolveURL(item.IconURL); + if (!this._checkLoadURIFromScript(iconUrl)) { + iconUrl = null; // If page can't load the icon, just ignore it + } + } + + installData.uris.push(url.spec); + installData.hashes.push(item.Hash || null); + installData.names.push(name); + installData.icons.push(iconUrl ? iconUrl.spec : null); + } + + return this._mediator.install(installData, this._principal, callback, this._window); + }, + + startSoftwareUpdate: function(url, flags) { + let filename = Services.io.newURI(url, null, null) + .QueryInterface(Ci.nsIURL) + .filename; + let args = {}; + args[filename] = { "URL": url }; + return this.install(args); + }, + + installChrome: function(type, url, skin) { + return this.startSoftwareUpdate(url); + }, + + _resolveURL: function (url) { + return Services.io.newURI(url, null, this._url); + }, + + _checkLoadURIFromScript: function(uri) { + let secman = Services.scriptSecurityManager; + try { + secman.checkLoadURIWithPrincipal(this._principal, + uri, + secman.DISALLOW_INHERIT_PRINCIPAL); + return true; + } + catch(e) { + return false; + } + }, + + classID: Components.ID("{9df8ef2b-94da-45c9-ab9f-132eb55fddf1}"), + contractID: "@mozilla.org/addons/installtrigger;1", + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIDOMGlobalPropertyInitializer]) +}; + + + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InstallTrigger]); diff --git a/toolkit/mozapps/extensions/amWebInstallListener.js b/toolkit/mozapps/extensions/amWebInstallListener.js new file mode 100644 index 000000000..901beef07 --- /dev/null +++ b/toolkit/mozapps/extensions/amWebInstallListener.js @@ -0,0 +1,342 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This is a default implementation of amIWebInstallListener that should work + * for most applications but can be overriden. It notifies the observer service + * about blocked installs. For normal installs it pops up an install + * confirmation when all the add-ons have been downloaded. + */ + +"use strict"; + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cr = Components.results; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "PromptUtils", "resource://gre/modules/SharedPromptUtils.jsm"); + +const URI_XPINSTALL_DIALOG = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; + +// Installation can begin from any of these states +const READY_STATES = [ + AddonManager.STATE_AVAILABLE, + AddonManager.STATE_DOWNLOAD_FAILED, + AddonManager.STATE_INSTALL_FAILED, + AddonManager.STATE_CANCELLED +]; + +Cu.import("resource://gre/modules/Log.jsm"); +const LOGGER_ID = "addons.weblistener"; + +// Create a new logger for use by the Addons Web Listener +// (Requires AddonManager.jsm) +let logger = Log.repository.getLogger(LOGGER_ID); + +function notifyObservers(aTopic, aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, aTopic, null); +} + +/** + * Creates a new installer to monitor downloads and prompt to install when + * ready + * + * @param aBrowser + * The browser that started the installations + * @param aUrl + * The URL that started the installations + * @param aInstalls + * An array of AddonInstalls + */ +function Installer(aBrowser, aUrl, aInstalls) { + this.browser = aBrowser; + this.url = aUrl; + this.downloads = aInstalls; + this.installed = []; + + notifyObservers("addon-install-started", aBrowser, aUrl, aInstalls); + + aInstalls.forEach(function(aInstall) { + aInstall.addListener(this); + + // Start downloading if it hasn't already begun + if (READY_STATES.indexOf(aInstall.state) != -1) + aInstall.install(); + }, this); + + this.checkAllDownloaded(); +} + +Installer.prototype = { + browser: null, + downloads: null, + installed: null, + isDownloading: true, + + /** + * Checks if all downloads are now complete and if so prompts to install. + */ + checkAllDownloaded: function Installer_checkAllDownloaded() { + // Prevent re-entrancy caused by the confirmation dialog cancelling unwanted + // installs. + if (!this.isDownloading) + return; + + var failed = []; + var installs = []; + + for (let install of this.downloads) { + switch (install.state) { + case AddonManager.STATE_AVAILABLE: + case AddonManager.STATE_DOWNLOADING: + // Exit early if any add-ons haven't started downloading yet or are + // still downloading + return; + case AddonManager.STATE_DOWNLOAD_FAILED: + failed.push(install); + break; + case AddonManager.STATE_DOWNLOADED: + // App disabled items are not compatible and so fail to install + if (install.addon.appDisabled) + failed.push(install); + else + installs.push(install); + + if (install.linkedInstalls) { + install.linkedInstalls.forEach(function(aInstall) { + aInstall.addListener(this); + // App disabled items are not compatible and so fail to install + if (aInstall.addon.appDisabled) + failed.push(aInstall); + else + installs.push(aInstall); + }, this); + } + break; + case AddonManager.STATE_CANCELLED: + // Just ignore cancelled downloads + break; + default: + logger.warn("Download of " + install.sourceURI.spec + " in unexpected state " + + install.state); + } + } + + this.isDownloading = false; + this.downloads = installs; + + if (failed.length > 0) { + // Stop listening and cancel any installs that are failed because of + // compatibility reasons. + failed.forEach(function(aInstall) { + if (aInstall.state == AddonManager.STATE_DOWNLOADED) { + aInstall.removeListener(this); + aInstall.cancel(); + } + }, this); + notifyObservers("addon-install-failed", this.browser, this.url, failed); + } + + // If none of the downloads were successful then exit early + if (this.downloads.length == 0) + return; + + // Check for a custom installation prompt that may be provided by the + // applicaton + if ("@mozilla.org/addons/web-install-prompt;1" in Cc) { + try { + let prompt = Cc["@mozilla.org/addons/web-install-prompt;1"]. + getService(Ci.amIWebInstallPrompt); + prompt.confirm(this.browser, this.url, this.downloads, this.downloads.length); + return; + } + catch (e) {} + } + + let args = {}; + args.url = this.url; + args.installs = this.downloads; + args.wrappedJSObject = args; + + try { + Cc["@mozilla.org/base/telemetry;1"]. + getService(Ci.nsITelemetry). + getHistogramById("SECURITY_UI"). + add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL); + let parentWindow = null; + if (this.browser) { + parentWindow = this.browser.ownerDocument.defaultView; + PromptUtils.fireDialogEvent(parentWindow, "DOMWillOpenModalDialog", this.browser); + } + Services.ww.openWindow(parentWindow, URI_XPINSTALL_DIALOG, + null, "chrome,modal,centerscreen", args); + } catch (e) { + logger.warn("Exception showing install confirmation dialog", e); + this.downloads.forEach(function(aInstall) { + aInstall.removeListener(this); + // Cancel the installs, as currently there is no way to make them fail + // from here. + aInstall.cancel(); + }, this); + notifyObservers("addon-install-cancelled", this.browser, this.url, + this.downloads); + } + }, + + /** + * Checks if all installs are now complete and if so notifies observers. + */ + checkAllInstalled: function Installer_checkAllInstalled() { + var failed = []; + + for (let install of this.downloads) { + switch(install.state) { + case AddonManager.STATE_DOWNLOADED: + case AddonManager.STATE_INSTALLING: + // Exit early if any add-ons haven't started installing yet or are + // still installing + return; + case AddonManager.STATE_INSTALL_FAILED: + failed.push(install); + break; + } + } + + this.downloads = null; + + if (failed.length > 0) + notifyObservers("addon-install-failed", this.browser, this.url, failed); + + if (this.installed.length > 0) + notifyObservers("addon-install-complete", this.browser, this.url, this.installed); + this.installed = null; + }, + + onDownloadCancelled: function Installer_onDownloadCancelled(aInstall) { + aInstall.removeListener(this); + this.checkAllDownloaded(); + }, + + onDownloadFailed: function Installer_onDownloadFailed(aInstall) { + aInstall.removeListener(this); + this.checkAllDownloaded(); + }, + + onDownloadEnded: function Installer_onDownloadEnded(aInstall) { + this.checkAllDownloaded(); + return false; + }, + + onInstallCancelled: function Installer_onInstallCancelled(aInstall) { + aInstall.removeListener(this); + this.checkAllInstalled(); + }, + + onInstallFailed: function Installer_onInstallFailed(aInstall) { + aInstall.removeListener(this); + this.checkAllInstalled(); + }, + + onInstallEnded: function Installer_onInstallEnded(aInstall) { + aInstall.removeListener(this); + this.installed.push(aInstall); + + // If installing a theme that is disabled and can be enabled then enable it + if (aInstall.addon.type == "theme" && + aInstall.addon.userDisabled == true && + aInstall.addon.appDisabled == false) { + aInstall.addon.userDisabled = false; + } + + this.checkAllInstalled(); + } +}; + +function extWebInstallListener() { +} + +extWebInstallListener.prototype = { + /** + * @see amIWebInstallListener.idl + */ + onWebInstallDisabled: function extWebInstallListener_onWebInstallDisabled(aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, "addon-install-disabled", null); + }, + + /** + * @see amIWebInstallListener.idl + */ + onWebInstallOriginBlocked: function extWebInstallListener_onWebInstallOriginBlocked(aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + install: function onWebInstallBlocked_install() { + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, "addon-install-origin-blocked", null); + + return false; + }, + + /** + * @see amIWebInstallListener.idl + */ + onWebInstallBlocked: function extWebInstallListener_onWebInstallBlocked(aBrowser, aUri, aInstalls) { + let info = { + browser: aBrowser, + originatingURI: aUri, + installs: aInstalls, + + install: function onWebInstallBlocked_install() { + new Installer(this.browser, this.originatingURI, this.installs); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallInfo]) + }; + Services.obs.notifyObservers(info, "addon-install-blocked", null); + + return false; + }, + + /** + * @see amIWebInstallListener.idl + */ + onWebInstallRequested: function extWebInstallListener_onWebInstallRequested(aBrowser, aUri, aInstalls) { + new Installer(aBrowser, aUri, aInstalls); + + // We start the installs ourself + return false; + }, + + classDescription: "XPI Install Handler", + contractID: "@mozilla.org/addons/web-install-listener;1", + classID: Components.ID("{0f38e086-89a3-40a5-8ffc-9b694de1d04a}"), + QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallListener, + Ci.amIWebInstallListener2]) +}; + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([extWebInstallListener]); diff --git a/toolkit/mozapps/extensions/content/OpenH264-license.txt b/toolkit/mozapps/extensions/content/OpenH264-license.txt new file mode 100644 index 000000000..ad37989b8 --- /dev/null +++ b/toolkit/mozapps/extensions/content/OpenH264-license.txt @@ -0,0 +1,59 @@ +------------------------------------------------------- +About The Cisco-Provided Binary of OpenH264 Video Codec +------------------------------------------------------- + +Cisco provides this program under the terms of the BSD license. + +Additionally, this binary is licensed under Cisco’s AVC/H.264 Patent Portfolio License from MPEG LA, at no cost to you, provided that the requirements and conditions shown below in the AVC/H.264 Patent Portfolio sections are met. + +As with all AVC/H.264 codecs, you may also obtain your own patent license from MPEG LA or from the individual patent owners, or proceed at your own risk. Your rights from Cisco under the BSD license are not affected by this choice. + +For more information on the OpenH264 binary licensing, please see the OpenH264 FAQ found at http://www.openh264.org/faq.html#binary + +A corresponding source code to this binary program is available under the same BSD terms, which can be found at http://www.openh264.org + +----------- +BSD License +----------- + +Copyright © 2014 Cisco Systems, Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------- +AVC/H.264 Patent Portfolio License Notice +----------------------------------------- + +The binary form of this Software is distributed by Cisco under the AVC/H.264 Patent Portfolio License from MPEG LA, and is subject to the following requirements, which may or may not be applicable to your use of this software: + +THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD (“AVC VIDEO”) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE HTTP://WWW.MPEGLA.COM + +Accordingly, please be advised that content providers and broadcasters using AVC/H.264 in their service may be required to obtain a separate use license from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 LICENSE TERMS from MPEG LA found at http://www.openh264.org/mpegla + +--------------------------------------------- +AVC/H.264 Patent Portfolio License Conditions +--------------------------------------------- + +In addition, the Cisco-provided binary of this Software is licensed under Cisco's license from MPEG LA only if the following conditions are met: + +1. The Cisco-provided binary is separately downloaded to an end user’s device, and not integrated into or combined with third party software prior to being downloaded to the end user’s device; + +2. The end user must have the ability to control (e.g., to enable, disable, or re-enable) the use of the Cisco-provided binary; + +3. Third party software, in the location where end users can control the use of the Cisco-provided binary, must display the following text: + + "OpenH264 Video Codec provided by Cisco Systems, Inc." + +4. Any third-party software that makes use of the Cisco-provided binary must reproduce all of the above text, as well as this last condition, in the EULA and/or in another location where licensing information is to be presented to the end user. + + + + v1.0 diff --git a/toolkit/mozapps/extensions/content/about.js b/toolkit/mozapps/extensions/content/about.js new file mode 100644 index 000000000..49ca4acc1 --- /dev/null +++ b/toolkit/mozapps/extensions/content/about.js @@ -0,0 +1,97 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +function init() { + var addon = window.arguments[0]; + var extensionsStrings = document.getElementById("extensionsStrings"); + + document.documentElement.setAttribute("addontype", addon.type); + + if (addon.iconURL) { + var extensionIcon = document.getElementById("extensionIcon"); + extensionIcon.src = addon.iconURL; + } + + document.title = extensionsStrings.getFormattedString("aboutWindowTitle", [addon.name]); + var extensionName = document.getElementById("extensionName"); + extensionName.textContent = addon.name; + + var extensionVersion = document.getElementById("extensionVersion"); + if (addon.version) + extensionVersion.setAttribute("value", extensionsStrings.getFormattedString("aboutWindowVersionString", [addon.version])); + else + extensionVersion.hidden = true; + + var extensionDescription = document.getElementById("extensionDescription"); + if (addon.description) + extensionDescription.textContent = addon.description; + else + extensionDescription.hidden = true; + + var numDetails = 0; + + var extensionCreator = document.getElementById("extensionCreator"); + if (addon.creator) { + extensionCreator.setAttribute("value", addon.creator); + numDetails++; + } else { + extensionCreator.hidden = true; + var extensionCreatorLabel = document.getElementById("extensionCreatorLabel"); + extensionCreatorLabel.hidden = true; + } + + var extensionHomepage = document.getElementById("extensionHomepage"); + var homepageURL = addon.homepageURL; + if (homepageURL) { + extensionHomepage.setAttribute("homepageURL", homepageURL); + extensionHomepage.setAttribute("tooltiptext", homepageURL); + numDetails++; + } else { + extensionHomepage.hidden = true; + } + + numDetails += appendToList("extensionDevelopers", "developersBox", addon.developers); + numDetails += appendToList("extensionTranslators", "translatorsBox", addon.translators); + numDetails += appendToList("extensionContributors", "contributorsBox", addon.contributors); + + if (numDetails == 0) { + var groove = document.getElementById("groove"); + groove.hidden = true; + var extensionDetailsBox = document.getElementById("extensionDetailsBox"); + extensionDetailsBox.hidden = true; + } + + var acceptButton = document.documentElement.getButton("accept"); + acceptButton.label = extensionsStrings.getString("aboutWindowCloseButton"); + + setTimeout(sizeToContent, 0); +} + +function appendToList(aHeaderId, aNodeId, aItems) { + var header = document.getElementById(aHeaderId); + var node = document.getElementById(aNodeId); + + if (!aItems || aItems.length == 0) { + header.hidden = true; + return 0; + } + + for (let currentItem of aItems) { + var label = document.createElement("label"); + label.textContent = currentItem; + label.setAttribute("class", "contributor"); + node.appendChild(label); + } + + return aItems.length; +} + +function loadHomepage(aEvent) { + window.close(); + openURL(aEvent.target.getAttribute("homepageURL")); +} diff --git a/toolkit/mozapps/extensions/content/about.xul b/toolkit/mozapps/extensions/content/about.xul new file mode 100644 index 000000000..6effcf37a --- /dev/null +++ b/toolkit/mozapps/extensions/content/about.xul @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + +

Test page for the discovery pane

+

Direct install

+

JS install

+ + diff --git a/toolkit/mozapps/extensions/test/browser/head.js b/toolkit/mozapps/extensions/test/browser/head.js new file mode 100644 index 000000000..8e96b9b3f --- /dev/null +++ b/toolkit/mozapps/extensions/test/browser/head.js @@ -0,0 +1,1393 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +let tmp = {}; +Components.utils.import("resource://gre/modules/AddonManager.jsm", tmp); +Components.utils.import("resource://gre/modules/Log.jsm", tmp); +let AddonManager = tmp.AddonManager; +let AddonManagerPrivate = tmp.AddonManagerPrivate; +let Log = tmp.Log; + +var pathParts = gTestPath.split("/"); +// Drop the test filename +pathParts.splice(pathParts.length - 1, pathParts.length); + +var gTestInWindow = /-window$/.test(pathParts[pathParts.length - 1]); + +// Drop the UI type +if (gTestInWindow) { + pathParts.splice(pathParts.length - 1, pathParts.length); +} + +const RELATIVE_DIR = pathParts.slice(4).join("/") + "/"; + +const TESTROOT = "http://example.com/" + RELATIVE_DIR; +const TESTROOT2 = "http://example.org/" + RELATIVE_DIR; +const CHROMEROOT = pathParts.join("/") + "/"; +const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; +const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; +const PREF_XPI_ENABLED = "xpinstall.enabled"; +const PREF_UPDATEURL = "extensions.update.url"; +const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled"; +const PREF_UI_LASTCATEGORY = "extensions.ui.lastCategory"; + +const MANAGER_URI = "about:addons"; +const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults"; +const PREF_STRICT_COMPAT = "extensions.strictCompatibility"; + +var PREF_CHECK_COMPATIBILITY; +(function() { + var channel = "default"; + try { + channel = Services.prefs.getCharPref("app.update.channel"); + } catch (e) { } + if (channel != "aurora" && + channel != "beta" && + channel != "release") { + var version = "nightly"; + } else { + version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1"); + } + PREF_CHECK_COMPATIBILITY = "extensions.checkCompatibility." + version; +})(); + +var gPendingTests = []; +var gTestsRun = 0; +var gTestStart = null; + +var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window); + +var gRestorePrefs = [{name: PREF_LOGGING_ENABLED}, + {name: "extensions.webservice.discoverURL"}, + {name: "extensions.update.url"}, + {name: "extensions.update.background.url"}, + {name: "extensions.update.enabled"}, + {name: "extensions.update.autoUpdateDefault"}, + {name: "extensions.getAddons.get.url"}, + {name: "extensions.getAddons.getWithPerformance.url"}, + {name: "extensions.getAddons.search.browseURL"}, + {name: "extensions.getAddons.search.url"}, + {name: "extensions.getAddons.cache.enabled"}, + {name: "devtools.chrome.enabled"}, + {name: "devtools.debugger.remote-enabled"}, + {name: PREF_SEARCH_MAXRESULTS}, + {name: PREF_STRICT_COMPAT}, + {name: PREF_CHECK_COMPATIBILITY}]; + +for (let pref of gRestorePrefs) { + if (!Services.prefs.prefHasUserValue(pref.name)) { + pref.type = "clear"; + continue; + } + pref.type = Services.prefs.getPrefType(pref.name); + if (pref.type == Services.prefs.PREF_BOOL) + pref.value = Services.prefs.getBoolPref(pref.name); + else if (pref.type == Services.prefs.PREF_INT) + pref.value = Services.prefs.getIntPref(pref.name); + else if (pref.type == Services.prefs.PREF_STRING) + pref.value = Services.prefs.getCharPref(pref.name); +} + +// Turn logging on for all tests +Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); + +// Helper to register test failures and close windows if any are left open +function checkOpenWindows(aWindowID) { + let windows = Services.wm.getEnumerator(aWindowID); + let found = false; + while (windows.hasMoreElements()) { + let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow); + if (!win.closed) { + found = true; + win.close(); + } + } + if (found) + ok(false, "Found unexpected " + aWindowID + " window still open"); +} + +// Tools to disable and re-enable the background update and blocklist timers +// so that tests can protect themselves from unwanted timer events. +let gCatMan = Components.classes["@mozilla.org/categorymanager;1"] + .getService(Components.interfaces.nsICategoryManager); +// Default values from toolkit/mozapps/extensions/extensions.manifest, but disable*UpdateTimer() +// records the actual value so we can put it back in enable*UpdateTimer() +let backgroundUpdateConfig = "@mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400"; +let blocklistUpdateConfig = "@mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400"; + +let UTIMER = "update-timer"; +let AMANAGER = "addonManager"; +let BLOCKLIST = "nsBlocklistService"; + +function disableBackgroundUpdateTimer() { + info("Disabling " + UTIMER + " " + AMANAGER); + backgroundUpdateConfig = gCatMan.getCategoryEntry(UTIMER, AMANAGER); + gCatMan.deleteCategoryEntry(UTIMER, AMANAGER, true); +} + +function enableBackgroundUpdateTimer() { + info("Enabling " + UTIMER + " " + AMANAGER); + gCatMan.addCategoryEntry(UTIMER, AMANAGER, backgroundUpdateConfig, false, true); +} + +function disableBlocklistUpdateTimer() { + info("Disabling " + UTIMER + " " + BLOCKLIST); + blocklistUpdateConfig = gCatMan.getCategoryEntry(UTIMER, BLOCKLIST); + gCatMan.deleteCategoryEntry(UTIMER, BLOCKLIST, true); +} + +function enableBlocklistUpdateTimer() { + info("Enabling " + UTIMER + " " + BLOCKLIST); + gCatMan.addCategoryEntry(UTIMER, BLOCKLIST, blocklistUpdateConfig, false, true); +} + +registerCleanupFunction(function() { + // Restore prefs + for (let pref of gRestorePrefs) { + if (pref.type == "clear") + Services.prefs.clearUserPref(pref.name); + else if (pref.type == Services.prefs.PREF_BOOL) + Services.prefs.setBoolPref(pref.name, pref.value); + else if (pref.type == Services.prefs.PREF_INT) + Services.prefs.setIntPref(pref.name, pref.value); + else if (pref.type == Services.prefs.PREF_STRING) + Services.prefs.setCharPref(pref.name, pref.value); + } + + // Throw an error if the add-ons manager window is open anywhere + checkOpenWindows("Addons:Manager"); + checkOpenWindows("Addons:Compatibility"); + checkOpenWindows("Addons:Install"); + + return new Promise((resolve, reject) => AddonManager.getAllInstalls(resolve)) + .then(aInstalls => { + for (let install of aInstalls) { + if (install instanceof MockInstall) + continue; + + ok(false, "Should not have seen an install of " + install.sourceURI.spec + " in state " + install.state); + install.cancel(); + } + }); +}); + +function log_exceptions(aCallback, ...aArgs) { + try { + return aCallback.apply(null, aArgs); + } + catch (e) { + info("Exception thrown: " + e); + throw e; + } +} + +function log_callback(aPromise, aCallback) { + aPromise.then(aCallback) + .then(null, e => info("Exception thrown: " + e)); + return aPromise; +} + +function add_test(test) { + gPendingTests.push(test); +} + +function run_next_test() { + // Make sure we're not calling run_next_test from inside an add_task() test + // We're inside the browser_test.js 'testScope' here + if (this.__tasks) { + throw new Error("run_next_test() called from an add_task() test function. " + + "run_next_test() should not be called from inside add_task() " + + "under any circumstances!"); + } + if (gTestsRun > 0) + info("Test " + gTestsRun + " took " + (Date.now() - gTestStart) + "ms"); + + if (gPendingTests.length == 0) { + executeSoon(end_test); + return; + } + + gTestsRun++; + var test = gPendingTests.shift(); + if (test.name) + info("Running test " + gTestsRun + " (" + test.name + ")"); + else + info("Running test " + gTestsRun); + + gTestStart = Date.now(); + executeSoon(() => log_exceptions(test)); +} + +function get_addon_file_url(aFilename) { + try { + var cr = Cc["@mozilla.org/chrome/chrome-registry;1"]. + getService(Ci.nsIChromeRegistry); + var fileurl = cr.convertChromeURL(makeURI(CHROMEROOT + "addons/" + aFilename)); + return fileurl.QueryInterface(Ci.nsIFileURL); + } catch(ex) { + var jar = getJar(CHROMEROOT + "addons/" + aFilename); + var tmpDir = extractJarToTmp(jar); + tmpDir.append(aFilename); + + return Services.io.newFileURI(tmpDir).QueryInterface(Ci.nsIFileURL); + } +} + +function get_test_items_in_list(aManager) { + var tests = "@tests.mozilla.org"; + + let view = aManager.document.getElementById("view-port").selectedPanel; + let listid = view.id == "search-view" ? "search-list" : "addon-list"; + let item = aManager.document.getElementById(listid).firstChild; + let items = []; + + while (item) { + if (item.localName != "richlistitem") { + item = item.nextSibling; + continue; + } + + if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests) + items.push(item); + item = item.nextSibling; + } + + return items; +} + +function check_all_in_list(aManager, aIds, aIgnoreExtras) { + var doc = aManager.document; + var view = doc.getElementById("view-port").selectedPanel; + var listid = view.id == "search-view" ? "search-list" : "addon-list"; + var list = doc.getElementById(listid); + + var inlist = []; + var node = list.firstChild; + while (node) { + if (node.value) + inlist.push(node.value); + node = node.nextSibling; + } + + for (let id of aIds) { + if (inlist.indexOf(id) == -1) + ok(false, "Should find " + id + " in the list"); + } + + if (aIgnoreExtras) + return; + + for (let inlistItem of inlist) { + if (aIds.indexOf(inlistItem) == -1) + ok(false, "Shouldn't have seen " + inlistItem + " in the list"); + } +} + +function get_addon_element(aManager, aId) { + var doc = aManager.document; + var view = doc.getElementById("view-port").selectedPanel; + var listid = "addon-list"; + if (view.id == "search-view") + listid = "search-list"; + else if (view.id == "updates-view") + listid = "updates-list"; + var list = doc.getElementById(listid); + + var node = list.firstChild; + while (node) { + if (node.value == aId) + return node; + node = node.nextSibling; + } + return null; +} + +function wait_for_view_load(aManagerWindow, aCallback, aForceWait, aLongerTimeout) { + requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); + + if (!aForceWait && !aManagerWindow.gViewController.isLoading) { + log_exceptions(aCallback, aManagerWindow); + return; + } + + aManagerWindow.document.addEventListener("ViewChanged", function() { + aManagerWindow.document.removeEventListener("ViewChanged", arguments.callee, false); + log_exceptions(aCallback, aManagerWindow); + }, false); +} + +function wait_for_manager_load(aManagerWindow, aCallback) { + if (!aManagerWindow.gIsInitializing) { + log_exceptions(aCallback, aManagerWindow); + return; + } + + info("Waiting for initialization"); + aManagerWindow.document.addEventListener("Initialized", function() { + aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false); + log_exceptions(aCallback, aManagerWindow); + }, false); +} + +function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) { + let p = new Promise((resolve, reject) => { + + function setup_manager(aManagerWindow) { + if (aLoadCallback) + log_exceptions(aLoadCallback, aManagerWindow); + + if (aView) + aManagerWindow.loadView(aView); + + ok(aManagerWindow != null, "Should have an add-ons manager window"); + is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI"); + + waitForFocus(function() { + info("window has focus, waiting for manager load"); + wait_for_manager_load(aManagerWindow, function() { + info("Manager waiting for view load"); + wait_for_view_load(aManagerWindow, function() { + resolve(aManagerWindow); + }, null, aLongerTimeout); + }); + }, aManagerWindow); + } + + if (gUseInContentUI) { + info("Loading manager window in tab"); + Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.removeObserver(arguments.callee, aTopic); + if (aSubject.location.href != MANAGER_URI) { + info("Ignoring load event for " + aSubject.location.href); + return; + } + setup_manager(aSubject); + }, "EM-loaded", false); + + gBrowser.selectedTab = gBrowser.addTab(); + switchToTabHavingURI(MANAGER_URI, true); + } else { + info("Loading manager window in dialog"); + Services.obs.addObserver(function (aSubject, aTopic, aData) { + Services.obs.removeObserver(arguments.callee, aTopic); + setup_manager(aSubject); + }, "EM-loaded", false); + + openDialog(MANAGER_URI); + } + }); + + // The promise resolves with the manager window, so it is passed to the callback + return log_callback(p, aCallback); +} + +function close_manager(aManagerWindow, aCallback, aLongerTimeout) { + let p = new Promise((resolve, reject) => { + requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2); + + ok(aManagerWindow != null, "Should have an add-ons manager window to close"); + is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI"); + + aManagerWindow.addEventListener("unload", function() { + try { + dump("Manager window unload handler\n"); + this.removeEventListener("unload", arguments.callee, false); + resolve(); + } catch(e) { + reject(e); + } + }, false); + }); + + info("Telling manager window to close"); + aManagerWindow.close(); + info("Manager window close() call returned"); + + return log_callback(p, aCallback); +} + +function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) { + if (!aManagerWindow) { + return open_manager(aView, aCallback, aLoadCallback); + } + + return close_manager(aManagerWindow) + .then(() => open_manager(aView, aCallback, aLoadCallback)); +} + +function wait_for_window_open(aCallback) { + Services.wm.addListener({ + onOpenWindow: function(aWindow) { + Services.wm.removeListener(this); + + let domwindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + domwindow.addEventListener("load", function() { + domwindow.removeEventListener("load", arguments.callee, false); + executeSoon(function() { + aCallback(domwindow); + }); + }, false); + }, + + onCloseWindow: function(aWindow) { + }, + + onWindowTitleChange: function(aWindow, aTitle) { + } + }); +} + +function get_string(aName, ...aArgs) { + var bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/extensions.properties"); + if (aArgs.length == 0) + return bundle.GetStringFromName(aName); + return bundle.formatStringFromName(aName, aArgs, aArgs.length); +} + +function formatDate(aDate) { + return Cc["@mozilla.org/intl/scriptabledateformat;1"] + .getService(Ci.nsIScriptableDateFormat) + .FormatDate("", + Ci.nsIScriptableDateFormat.dateFormatLong, + aDate.getFullYear(), + aDate.getMonth() + 1, + aDate.getDate() + ); +} + +function is_hidden(aElement) { + var style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, ""); + if (style.display == "none") + return true; + if (style.visibility != "visible") + return true; + + // Hiding a parent element will hide all its children + if (aElement.parentNode != aElement.ownerDocument) + return is_hidden(aElement.parentNode); + + return false; +} + +function is_element_visible(aElement, aMsg) { + isnot(aElement, null, "Element should not be null, when checking visibility"); + ok(!is_hidden(aElement), aMsg || (aElement + " should be visible")); +} + +function is_element_hidden(aElement, aMsg) { + isnot(aElement, null, "Element should not be null, when checking visibility"); + ok(is_hidden(aElement), aMsg || (aElement + " should be hidden")); +} + +/** + * Install an add-on and call a callback when complete. + * + * The callback will receive the Addon for the installed add-on. + */ +function install_addon(path, cb, pathPrefix=TESTROOT) { + let p = new Promise((resolve, reject) => { + AddonManager.getInstallForURL(pathPrefix + path, (install) => { + install.addListener({ + onInstallEnded: () => resolve(install.addon), + }); + + install.install(); + }, "application/x-xpinstall"); + }); + + return log_callback(p, cb); +} + +function CategoryUtilities(aManagerWindow) { + this.window = aManagerWindow; + + var self = this; + this.window.addEventListener("unload", function() { + self.window.removeEventListener("unload", arguments.callee, false); + self.window = null; + }, false); +} + +CategoryUtilities.prototype = { + window: null, + + get selectedCategory() { + isnot(this.window, null, "Should not get selected category when manager window is not loaded"); + var selectedItem = this.window.document.getElementById("categories").selectedItem; + isnot(selectedItem, null, "A category should be selected"); + var view = this.window.gViewController.parseViewId(selectedItem.value); + return (view.type == "list") ? view.param : view.type; + }, + + get: function(aCategoryType, aAllowMissing) { + isnot(this.window, null, "Should not get category when manager window is not loaded"); + var categories = this.window.document.getElementById("categories"); + + var viewId = "addons://list/" + aCategoryType; + var items = categories.getElementsByAttribute("value", viewId); + if (items.length) + return items[0]; + + viewId = "addons://" + aCategoryType + "/"; + items = categories.getElementsByAttribute("value", viewId); + if (items.length) + return items[0]; + + if (!aAllowMissing) + ok(false, "Should have found a category with type " + aCategoryType); + return null; + }, + + getViewId: function(aCategoryType) { + isnot(this.window, null, "Should not get view id when manager window is not loaded"); + return this.get(aCategoryType).value; + }, + + isVisible: function(aCategory) { + isnot(this.window, null, "Should not check visible state when manager window is not loaded"); + if (aCategory.hasAttribute("disabled") && + aCategory.getAttribute("disabled") == "true") + return false; + + return !is_hidden(aCategory); + }, + + isTypeVisible: function(aCategoryType) { + return this.isVisible(this.get(aCategoryType)); + }, + + open: function(aCategory, aCallback) { + + isnot(this.window, null, "Should not open category when manager window is not loaded"); + ok(this.isVisible(aCategory), "Category should be visible if attempting to open it"); + + EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window); + let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve)); + + return log_callback(p, aCallback); + }, + + openType: function(aCategoryType, aCallback) { + return this.open(this.get(aCategoryType), aCallback); + } +} + +function CertOverrideListener(host, bits) { + this.host = host; + this.bits = bits; +} + +CertOverrideListener.prototype = { + host: null, + bits: null, + + getInterface: function (aIID) { + return this.QueryInterface(aIID); + }, + + QueryInterface: function(aIID) { + if (aIID.equals(Ci.nsIBadCertListener2) || + aIID.equals(Ci.nsIInterfaceRequestor) || + aIID.equals(Ci.nsISupports)) + return this; + + throw Components.Exception("No interface", Components.results.NS_ERROR_NO_INTERFACE); + }, + + notifyCertProblem: function (socketInfo, sslStatus, targetHost) { + var cert = sslStatus.QueryInterface(Components.interfaces.nsISSLStatus) + .serverCert; + var cos = Cc["@mozilla.org/security/certoverride;1"]. + getService(Ci.nsICertOverrideService); + cos.rememberValidityOverride(this.host, -1, cert, this.bits, false); + return true; + } +} + +// Add overrides for the bad certificates +function addCertOverride(host, bits) { + var req = new XMLHttpRequest(); + try { + req.open("GET", "https://" + host + "/", false); + req.channel.notificationCallbacks = new CertOverrideListener(host, bits); + req.send(null); + } + catch (e) { + // This request will fail since the SSL server is not trusted yet + } +} + +/***** Mock Provider *****/ + +function MockProvider(aUseAsyncCallbacks, aTypes) { + this.addons = []; + this.installs = []; + this.callbackTimers = []; + this.timerLocations = new Map(); + this.useAsyncCallbacks = (aUseAsyncCallbacks === undefined) ? true : aUseAsyncCallbacks; + this.types = (aTypes === undefined) ? [{ + id: "extension", + name: "Extensions", + uiPriority: 4000, + flags: AddonManager.TYPE_UI_VIEW_LIST | + AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL, + }] : aTypes; + + var self = this; + registerCleanupFunction(function() { + if (self.started) + self.unregister(); + }); + + this.register(); +} + +MockProvider.prototype = { + addons: null, + installs: null, + started: null, + apiDelay: 10, + callbackTimers: null, + timerLocations: null, + useAsyncCallbacks: null, + types: null, + + /***** Utility functions *****/ + + /** + * Register this provider with the AddonManager + */ + register: function MP_register() { + info("Registering mock add-on provider"); + AddonManagerPrivate.registerProvider(this, this.types); + }, + + /** + * Unregister this provider with the AddonManager + */ + unregister: function MP_unregister() { + info("Unregistering mock add-on provider"); + AddonManagerPrivate.unregisterProvider(this); + }, + + /** + * Adds an add-on to the list of add-ons that this provider exposes to the + * AddonManager, dispatching appropriate events in the process. + * + * @param aAddon + * The add-on to add + */ + addAddon: function MP_addAddon(aAddon) { + var oldAddons = this.addons.filter(function(aOldAddon) aOldAddon.id == aAddon.id); + var oldAddon = oldAddons.length > 0 ? oldAddons[0] : null; + + this.addons = this.addons.filter(function(aOldAddon) aOldAddon.id != aAddon.id); + + this.addons.push(aAddon); + aAddon._provider = this; + + if (!this.started) + return; + + let requiresRestart = (aAddon.operationsRequiringRestart & + AddonManager.OP_NEEDS_RESTART_INSTALL) != 0; + AddonManagerPrivate.callInstallListeners("onExternalInstall", null, aAddon, + oldAddon, requiresRestart) + }, + + /** + * Removes an add-on from the list of add-ons that this provider exposes to + * the AddonManager, dispatching the onUninstalled event in the process. + * + * @param aAddon + * The add-on to add + */ + removeAddon: function MP_removeAddon(aAddon) { + var pos = this.addons.indexOf(aAddon); + if (pos == -1) { + ok(false, "Tried to remove an add-on that wasn't registered with the mock provider"); + return; + } + + this.addons.splice(pos, 1); + + if (!this.started) + return; + + AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon); + }, + + /** + * Adds an add-on install to the list of installs that this provider exposes + * to the AddonManager, dispatching appropriate events in the process. + * + * @param aInstall + * The add-on install to add + */ + addInstall: function MP_addInstall(aInstall) { + this.installs.push(aInstall); + aInstall._provider = this; + + if (!this.started) + return; + + aInstall.callListeners("onNewInstall"); + }, + + removeInstall: function MP_removeInstall(aInstall) { + var pos = this.installs.indexOf(aInstall); + if (pos == -1) { + ok(false, "Tried to remove an install that wasn't registered with the mock provider"); + return; + } + + this.installs.splice(pos, 1); + }, + + /** + * Creates a set of mock add-on objects and adds them to the list of add-ons + * managed by this provider. + * + * @param aAddonProperties + * An array of objects containing properties describing the add-ons + * @return Array of the new MockAddons + */ + createAddons: function MP_createAddons(aAddonProperties) { + var newAddons = []; + for (let addonProp of aAddonProperties) { + let addon = new MockAddon(addonProp.id); + for (let prop in addonProp) { + if (prop == "id") + continue; + if (prop == "applyBackgroundUpdates") { + addon._applyBackgroundUpdates = addonProp[prop]; + continue; + } + if (prop == "appDisabled") { + addon._appDisabled = addonProp[prop]; + continue; + } + addon[prop] = addonProp[prop]; + } + if (!addon.optionsType && !!addon.optionsURL) + addon.optionsType = AddonManager.OPTIONS_TYPE_DIALOG; + + // Make sure the active state matches the passed in properties + addon.isActive = addon.shouldBeActive; + + this.addAddon(addon); + newAddons.push(addon); + } + + return newAddons; + }, + + /** + * Creates a set of mock add-on install objects and adds them to the list + * of installs managed by this provider. + * + * @param aInstallProperties + * An array of objects containing properties describing the installs + * @return Array of the new MockInstalls + */ + createInstalls: function MP_createInstalls(aInstallProperties) { + var newInstalls = []; + for (let installProp of aInstallProperties) { + let install = new MockInstall(installProp.name || null, + installProp.type || null, + null); + for (let prop in installProp) { + switch (prop) { + case "name": + case "type": + break; + case "sourceURI": + install[prop] = NetUtil.newURI(installProp[prop]); + break; + default: + install[prop] = installProp[prop]; + } + } + this.addInstall(install); + newInstalls.push(install); + } + + return newInstalls; + }, + + /***** AddonProvider implementation *****/ + + /** + * Called to initialize the provider. + */ + startup: function MP_startup() { + this.started = true; + }, + + /** + * Called when the provider should shutdown. + */ + shutdown: function MP_shutdown() { + if (this.callbackTimers.length) { + info("MockProvider: pending callbacks at shutdown(): calling immediately"); + } + while (this.callbackTimers.length > 0) { + // When we notify the callback timer, it removes itself from our array + let timer = this.callbackTimers[0]; + try { + let setAt = this.timerLocations.get(timer); + info("Notifying timer set at " + (setAt || "unknown location")); + timer.callback.notify(timer); + timer.cancel(); + } catch(e) { + info("Timer notify failed: " + e); + } + } + this.callbackTimers = []; + this.timerLocations = null; + + this.started = false; + }, + + /** + * Called to get an Addon with a particular ID. + * + * @param aId + * The ID of the add-on to retrieve + * @param aCallback + * A callback to pass the Addon to + */ + getAddonByID: function MP_getAddon(aId, aCallback) { + for (let addon of this.addons) { + if (addon.id == aId) { + this._delayCallback(aCallback, addon); + return; + } + } + + aCallback(null); + }, + + /** + * Called to get Addons of a particular type. + * + * @param aTypes + * An array of types to fetch. Can be null to get all types. + * @param callback + * A callback to pass an array of Addons to + */ + getAddonsByTypes: function MP_getAddonsByTypes(aTypes, aCallback) { + var addons = this.addons.filter(function(aAddon) { + if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) + return false; + return true; + }); + this._delayCallback(aCallback, addons); + }, + + /** + * Called to get Addons that have pending operations. + * + * @param aTypes + * An array of types to fetch. Can be null to get all types + * @param aCallback + * A callback to pass an array of Addons to + */ + getAddonsWithOperationsByTypes: function MP_getAddonsWithOperationsByTypes(aTypes, aCallback) { + var addons = this.addons.filter(function(aAddon) { + if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1) + return false; + return aAddon.pendingOperations != 0; + }); + this._delayCallback(aCallback, addons); + }, + + /** + * Called to get the current AddonInstalls, optionally restricting by type. + * + * @param aTypes + * An array of types or null to get all types + * @param aCallback + * A callback to pass the array of AddonInstalls to + */ + getInstallsByTypes: function MP_getInstallsByTypes(aTypes, aCallback) { + var installs = this.installs.filter(function(aInstall) { + // Appear to have actually removed cancelled installs from the provider + if (aInstall.state == AddonManager.STATE_CANCELLED) + return false; + + if (aTypes && aTypes.length > 0 && aTypes.indexOf(aInstall.type) == -1) + return false; + + return true; + }); + this._delayCallback(aCallback, installs); + }, + + /** + * Called when a new add-on has been enabled when only one add-on of that type + * can be enabled. + * + * @param aId + * The ID of the newly enabled add-on + * @param aType + * The type of the newly enabled add-on + * @param aPendingRestart + * true if the newly enabled add-on will only become enabled after a + * restart + */ + addonChanged: function MP_addonChanged(aId, aType, aPendingRestart) { + // Not implemented + }, + + /** + * Update the appDisabled property for all add-ons. + */ + updateAddonAppDisabledStates: function MP_updateAddonAppDisabledStates() { + // Not needed + }, + + /** + * Called to get an AddonInstall to download and install an add-on from a URL. + * + * @param aUrl + * The URL to be installed + * @param aHash + * A hash for the install + * @param aName + * A name for the install + * @param aIconURL + * An icon URL for the install + * @param aVersion + * A version for the install + * @param aLoadGroup + * An nsILoadGroup to associate requests with + * @param aCallback + * A callback to pass the AddonInstall to + */ + getInstallForURL: function MP_getInstallForURL(aUrl, aHash, aName, aIconURL, + aVersion, aLoadGroup, aCallback) { + // Not yet implemented + }, + + /** + * Called to get an AddonInstall to install an add-on from a local file. + * + * @param aFile + * The file to be installed + * @param aCallback + * A callback to pass the AddonInstall to + */ + getInstallForFile: function MP_getInstallForFile(aFile, aCallback) { + // Not yet implemented + }, + + /** + * Called to test whether installing add-ons is enabled. + * + * @return true if installing is enabled + */ + isInstallEnabled: function MP_isInstallEnabled() { + return false; + }, + + /** + * Called to test whether this provider supports installing a particular + * mimetype. + * + * @param aMimetype + * The mimetype to check for + * @return true if the mimetype is supported + */ + supportsMimetype: function MP_supportsMimetype(aMimetype) { + return false; + }, + + /** + * Called to test whether installing add-ons from a URI is allowed. + * + * @param aUri + * The URI being installed from + * @return true if installing is allowed + */ + isInstallAllowed: function MP_isInstallAllowed(aUri) { + return false; + }, + + + /***** Internal functions *****/ + + /** + * Delay calling a callback to fake a time-consuming async operation. + * The delay is specified by the apiDelay property, in milliseconds. + * Parameters to send to the callback should be specified as arguments after + * the aCallback argument. + * + * @param aCallback Callback to eventually call + */ + _delayCallback: function MP_delayCallback(aCallback, ...aArgs) { + if (!this.useAsyncCallbacks) { + aCallback(...aArgs); + return; + } + + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + // Need to keep a reference to the timer, so it doesn't get GC'ed + this.callbackTimers.push(timer); + // Capture a stack trace where the timer was set + // needs the 'new Error' hack until bug 1007656 + this.timerLocations.set(timer, Log.stackTrace(new Error("dummy"))); + timer.initWithCallback(() => { + let idx = this.callbackTimers.indexOf(timer); + if (idx == -1) { + dump("MockProvider._delayCallback lost track of timer set at " + + (this.timerLocations.get(timer) || "unknown location") + "\n"); + } else { + this.callbackTimers.splice(idx, 1); + } + this.timerLocations.delete(timer); + aCallback(...aArgs); + }, this.apiDelay, timer.TYPE_ONE_SHOT); + } +}; + +/***** Mock Addon object for the Mock Provider *****/ + +function MockAddon(aId, aName, aType, aOperationsRequiringRestart) { + // Only set required attributes. + this.id = aId || ""; + this.name = aName || ""; + this.type = aType || "extension"; + this.version = ""; + this.isCompatible = true; + this.isDebuggable = false; + this.providesUpdatesSecurely = true; + this.blocklistState = 0; + this._appDisabled = false; + this._userDisabled = false; + this._applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE; + this.scope = AddonManager.SCOPE_PROFILE; + this.isActive = true; + this.creator = ""; + this.pendingOperations = 0; + this._permissions = AddonManager.PERM_CAN_UNINSTALL | + AddonManager.PERM_CAN_ENABLE | + AddonManager.PERM_CAN_DISABLE | + AddonManager.PERM_CAN_UPGRADE; + this.operationsRequiringRestart = aOperationsRequiringRestart || + (AddonManager.OP_NEEDS_RESTART_INSTALL | + AddonManager.OP_NEEDS_RESTART_UNINSTALL | + AddonManager.OP_NEEDS_RESTART_ENABLE | + AddonManager.OP_NEEDS_RESTART_DISABLE); +} + +MockAddon.prototype = { + get shouldBeActive() { + return !this.appDisabled && !this._userDisabled && + !(this.pendingOperations & AddonManager.PENDING_UNINSTALL); + }, + + get appDisabled() { + return this._appDisabled; + }, + + set appDisabled(val) { + if (val == this._appDisabled) + return val; + + AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["appDisabled"]); + + var currentActive = this.shouldBeActive; + this._appDisabled = val; + var newActive = this.shouldBeActive; + this._updateActiveState(currentActive, newActive); + + return val; + }, + + get userDisabled() { + return this._userDisabled; + }, + + set userDisabled(val) { + if (val == this._userDisabled) + return val; + + var currentActive = this.shouldBeActive; + this._userDisabled = val; + var newActive = this.shouldBeActive; + this._updateActiveState(currentActive, newActive); + + return val; + }, + + get permissions() { + let permissions = this._permissions; + if (this.appDisabled || !this._userDisabled) + permissions &= ~AddonManager.PERM_CAN_ENABLE; + if (this.appDisabled || this._userDisabled) + permissions &= ~AddonManager.PERM_CAN_DISABLE; + return permissions; + }, + + set permissions(val) { + return this._permissions = val; + }, + + get applyBackgroundUpdates() { + return this._applyBackgroundUpdates; + }, + + set applyBackgroundUpdates(val) { + if (val != AddonManager.AUTOUPDATE_DEFAULT && + val != AddonManager.AUTOUPDATE_DISABLE && + val != AddonManager.AUTOUPDATE_ENABLE) { + ok(false, "addon.applyBackgroundUpdates set to an invalid value: " + val); + } + this._applyBackgroundUpdates = val; + AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["applyBackgroundUpdates"]); + }, + + isCompatibleWith: function(aAppVersion, aPlatformVersion) { + return true; + }, + + findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) { + // Tests can implement this if they need to + }, + + uninstall: function(aAlwaysAllowUndo = false) { + if ((this.operationsRequiringRestart & AddonManager.OP_NEED_RESTART_UNINSTALL) + && this.pendingOperations & AddonManager.PENDING_UNINSTALL) + throw Components.Exception("Add-on is already pending uninstall"); + + var needsRestart = aAlwaysAllowUndo || !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL); + this.pendingOperations |= AddonManager.PENDING_UNINSTALL; + AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart); + if (!needsRestart) { + this.pendingOperations -= AddonManager.PENDING_UNINSTALL; + this._provider.removeAddon(this); + } else if (!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE)) { + this.isActive = false; + } + }, + + cancelUninstall: function() { + if (!(this.pendingOperations & AddonManager.PENDING_UNINSTALL)) + throw Components.Exception("Add-on is not pending uninstall"); + + this.pendingOperations -= AddonManager.PENDING_UNINSTALL; + this.isActive = this.shouldBeActive; + AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); + }, + + _updateActiveState: function(currentActive, newActive) { + if (currentActive == newActive) + return; + + if (newActive == this.isActive) { + this.pendingOperations -= (newActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE); + AddonManagerPrivate.callAddonListeners("onOperationCancelled", this); + } + else if (newActive) { + var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE); + this.pendingOperations |= AddonManager.PENDING_ENABLE; + AddonManagerPrivate.callAddonListeners("onEnabling", this, needsRestart); + if (!needsRestart) { + this.isActive = newActive; + this.pendingOperations -= AddonManager.PENDING_ENABLE; + AddonManagerPrivate.callAddonListeners("onEnabled", this); + } + } + else { + var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE); + this.pendingOperations |= AddonManager.PENDING_DISABLE; + AddonManagerPrivate.callAddonListeners("onDisabling", this, needsRestart); + if (!needsRestart) { + this.isActive = newActive; + this.pendingOperations -= AddonManager.PENDING_DISABLE; + AddonManagerPrivate.callAddonListeners("onDisabled", this); + } + } + } +}; + +/***** Mock AddonInstall object for the Mock Provider *****/ + +function MockInstall(aName, aType, aAddonToInstall) { + this.name = aName || ""; + // Don't expose type until download completed + this._type = aType || "extension"; + this.type = null; + this.version = "1.0"; + this.iconURL = ""; + this.infoURL = ""; + this.state = AddonManager.STATE_AVAILABLE; + this.error = 0; + this.sourceURI = null; + this.file = null; + this.progress = 0; + this.maxProgress = -1; + this.certificate = null; + this.certName = ""; + this.existingAddon = null; + this.addon = null; + this._addonToInstall = aAddonToInstall; + this.listeners = []; + + // Another type of install listener for tests that want to check the results + // of code run from standard install listeners + this.testListeners = []; +} + +MockInstall.prototype = { + install: function() { + switch (this.state) { + case AddonManager.STATE_AVAILABLE: + this.state = AddonManager.STATE_DOWNLOADING; + if (!this.callListeners("onDownloadStarted")) { + this.state = AddonManager.STATE_CANCELLED; + this.callListeners("onDownloadCancelled"); + return; + } + + this.type = this._type; + + // Adding addon to MockProvider to be implemented when needed + if (this._addonToInstall) + this.addon = this._addonToInstall; + else { + this.addon = new MockAddon("", this.name, this.type); + this.addon.version = this.version; + this.addon.pendingOperations = AddonManager.PENDING_INSTALL; + } + this.addon.install = this; + if (this.existingAddon) { + if (!this.addon.id) + this.addon.id = this.existingAddon.id; + this.existingAddon.pendingUpgrade = this.addon; + this.existingAddon.pendingOperations |= AddonManager.PENDING_UPGRADE; + } + + this.state = AddonManager.STATE_DOWNLOADED; + this.callListeners("onDownloadEnded"); + + case AddonManager.STATE_DOWNLOADED: + this.state = AddonManager.STATE_INSTALLING; + if (!this.callListeners("onInstallStarted")) { + this.state = AddonManager.STATE_CANCELLED; + this.callListeners("onInstallCancelled"); + return; + } + + AddonManagerPrivate.callAddonListeners("onInstalling", this.addon); + + this.state = AddonManager.STATE_INSTALLED; + this.callListeners("onInstallEnded"); + break; + case AddonManager.STATE_DOWNLOADING: + case AddonManager.STATE_CHECKING: + case AddonManger.STATE_INSTALLING: + // Installation is already running + return; + default: + ok(false, "Cannot start installing when state = " + this.state); + } + }, + + cancel: function() { + switch (this.state) { + case AddonManager.STATE_AVAILABLE: + this.state = AddonManager.STATE_CANCELLED; + break; + case AddonManager.STATE_INSTALLED: + this.state = AddonManager.STATE_CANCELLED; + this._provider.removeInstall(this); + this.callListeners("onInstallCancelled"); + break; + default: + // Handling cancelling when downloading to be implemented when needed + ok(false, "Cannot cancel when state = " + this.state); + } + }, + + + addListener: function(aListener) { + if (!this.listeners.some(function(i) i == aListener)) + this.listeners.push(aListener); + }, + + removeListener: function(aListener) { + this.listeners = this.listeners.filter(function(i) i != aListener); + }, + + addTestListener: function(aListener) { + if (!this.testListeners.some(function(i) i == aListener)) + this.testListeners.push(aListener); + }, + + removeTestListener: function(aListener) { + this.testListeners = this.testListeners.filter(function(i) i != aListener); + }, + + callListeners: function(aMethod) { + var result = AddonManagerPrivate.callInstallListeners(aMethod, this.listeners, + this, this.addon); + + // Call test listeners after standard listeners to remove race condition + // between standard and test listeners + for (let listener of this.testListeners) { + try { + if (aMethod in listener) + if (listener[aMethod].call(listener, this, this.addon) === false) + result = false; + } + catch (e) { + ok(false, "Test listener threw exception: " + e); + } + } + + return result; + } +}; + +function waitForCondition(condition, nextTest, errorMsg) { + let tries = 0; + let interval = setInterval(function() { + if (tries >= 30) { + ok(false, errorMsg); + moveOn(); + } + var conditionPassed; + try { + conditionPassed = condition(); + } catch (e) { + ok(false, e + "\n" + e.stack); + conditionPassed = false; + } + if (conditionPassed) { + moveOn(); + } + tries++; + }, 100); + let moveOn = function() { clearInterval(interval); nextTest(); }; +} + +function getTestPluginTag() { + let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let tags = ph.getPluginTags(); + + // Find the test plugin + for (let i = 0; i < tags.length; i++) { + if (tags[i].name == "Test Plug-in") + return tags[i]; + } + ok(false, "Unable to find plugin"); + return null; +} diff --git a/toolkit/mozapps/extensions/test/browser/more_options.xul b/toolkit/mozapps/extensions/test/browser/more_options.xul new file mode 100644 index 000000000..4c8474a79 --- /dev/null +++ b/toolkit/mozapps/extensions/test/browser/more_options.xul @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/browser/moz.build b/toolkit/mozapps/extensions/test/browser/moz.build new file mode 100644 index 000000000..9acb42133 --- /dev/null +++ b/toolkit/mozapps/extensions/test/browser/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +BROWSER_CHROME_MANIFESTS += [ + 'browser-window.ini', + 'browser.ini', +] diff --git a/toolkit/mozapps/extensions/test/browser/options.xul b/toolkit/mozapps/extensions/test/browser/options.xul new file mode 100644 index 000000000..1b6827915 --- /dev/null +++ b/toolkit/mozapps/extensions/test/browser/options.xul @@ -0,0 +1,12 @@ + + + + + Description Text Node + + This is a test, +

+

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs b/toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs new file mode 100644 index 000000000..92bccd9ec --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/cookieRedirect.sjs @@ -0,0 +1,24 @@ +// Simple script redirects to the query part of the uri if the cookie "xpinstall" +// has the value "true", otherwise gives a 500 error. + +function handleRequest(request, response) +{ + let cookie = null; + if (request.hasHeader("Cookie")) { + let cookies = request.getHeader("Cookie").split(";"); + for (let i = 0; i < cookies.length; i++) { + if (cookies[i].substring(0, 10) == "xpinstall=") + cookie = cookies[i].substring(10); + } + } + + if (cookie == "true") { + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("Location", request.queryString); + response.write("See " + request.queryString); + } + else { + response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); + response.write("Invalid request"); + } +} diff --git a/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi b/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi new file mode 100644 index 000000000..35d7bd5e5 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi @@ -0,0 +1 @@ +This is a corrupt zip file diff --git a/toolkit/mozapps/extensions/test/xpinstall/empty.xpi b/toolkit/mozapps/extensions/test/xpinstall/empty.xpi new file mode 100644 index 000000000..74ed2b817 Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/empty.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/enabled.html b/toolkit/mozapps/extensions/test/xpinstall/enabled.html new file mode 100644 index 000000000..ec8513edc --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/enabled.html @@ -0,0 +1,23 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs b/toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs new file mode 100644 index 000000000..324a092a3 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/hashRedirect.sjs @@ -0,0 +1,15 @@ +// Simple script redirects takes the query part of te request and splits it on +// the | character. Anything before is included as the X-Target-Digest header +// the latter part is used as the url to redirect to + +function handleRequest(request, response) +{ + let pos = request.queryString.indexOf("|"); + let header = request.queryString.substring(0, pos); + let url = request.queryString.substring(pos + 1); + + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("X-Target-Digest", header); + response.setHeader("Location", url); + response.write("See " + url); +} diff --git a/toolkit/mozapps/extensions/test/xpinstall/head.js b/toolkit/mozapps/extensions/test/xpinstall/head.js new file mode 100644 index 000000000..90db29924 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/head.js @@ -0,0 +1,424 @@ +const RELATIVE_DIR = "toolkit/mozapps/extensions/test/xpinstall/"; + +const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR; +const TESTROOT2 = "http://example.org/browser/" + RELATIVE_DIR; +const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul"; +const PROMPT_URL = "chrome://global/content/commonDialog.xul"; +const ADDONS_URL = "chrome://mozapps/content/extensions/extensions.xul"; +const PREF_LOGGING_ENABLED = "extensions.logging.enabled"; +const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts"; +const PREF_INSTALL_REQUIRESECUREORIGIN = "extensions.install.requireSecureOrigin"; +const CHROME_NAME = "mochikit"; + +function getChromeRoot(path) { + if (path === undefined) { + return "chrome://" + CHROME_NAME + "/content/browser/" + RELATIVE_DIR + } + return getRootDirectory(path); +} + +function extractChromeRoot(path) { + var chromeRootPath = getChromeRoot(path); + var jar = getJar(chromeRootPath); + if (jar) { + var tmpdir = extractJarToTmp(jar); + return "file://" + tmpdir.path + "/"; + } + return chromeRootPath; +} + +/** + * This is a test harness designed to handle responding to UI during the process + * of installing an XPI. A test can set callbacks to hear about specific parts + * of the sequence. + * Before use setup must be called and finish must be called afterwards. + */ +var Harness = { + // If set then the callback is called when an install is attempted and + // software installation is disabled. + installDisabledCallback: null, + // If set then the callback is called when an install is attempted and + // then canceled. + installCancelledCallback: null, + // If set then the callback will be called when an install's origin is blocked. + installOriginBlockedCallback: null, + // If set then the callback will be called when an install is blocked by the + // whitelist. The callback should return true to continue with the install + // anyway. + installBlockedCallback: null, + // If set will be called in the event of authentication being needed to get + // the xpi. Should return a 2 element array of username and password, or + // null to not authenticate. + authenticationCallback: null, + // If set this will be called to allow checking the contents of the xpinstall + // confirmation dialog. The callback should return true to continue the install. + installConfirmCallback: null, + // If set will be called when downloading of an item has begun. + downloadStartedCallback: null, + // If set will be called during the download of an item. + downloadProgressCallback: null, + // If set will be called when an xpi fails to download. + downloadFailedCallback: null, + // If set will be called when an xpi download is cancelled. + downloadCancelledCallback: null, + // If set will be called when downloading of an item has ended. + downloadEndedCallback: null, + // If set will be called when installation by the extension manager of an xpi + // item starts + installStartedCallback: null, + // If set will be called when an xpi fails to install. + installFailedCallback: null, + // If set will be called when each xpi item to be installed completes + // installation. + installEndedCallback: null, + // If set will be called when all triggered items are installed or the install + // is canceled. + installsCompletedCallback: null, + // If set the harness will wait for this DOM event before calling + // installsCompletedCallback + finalContentEvent: null, + + waitingForEvent: false, + pendingCount: null, + installCount: null, + runningInstalls: null, + + waitingForFinish: false, + + // A unique value to return from the installConfirmCallback to indicate that + // the install UI shouldn't be closed automatically + leaveOpen: {}, + + // Setup and tear down functions + setup: function() { + if (!this.waitingForFinish) { + waitForExplicitFinish(); + this.waitingForFinish = true; + + Services.prefs.setBoolPref(PREF_INSTALL_REQUIRESECUREORIGIN, false); + + Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true); + Services.obs.addObserver(this, "addon-install-started", false); + Services.obs.addObserver(this, "addon-install-disabled", false); + Services.obs.addObserver(this, "addon-install-origin-blocked", false); + Services.obs.addObserver(this, "addon-install-blocked", false); + Services.obs.addObserver(this, "addon-install-failed", false); + Services.obs.addObserver(this, "addon-install-complete", false); + + AddonManager.addInstallListener(this); + + Services.wm.addListener(this); + + var self = this; + registerCleanupFunction(function() { + Services.prefs.clearUserPref(PREF_LOGGING_ENABLED); + Services.prefs.clearUserPref(PREF_INSTALL_REQUIRESECUREORIGIN); + Services.obs.removeObserver(self, "addon-install-started"); + Services.obs.removeObserver(self, "addon-install-disabled"); + Services.obs.removeObserver(self, "addon-install-origin-blocked"); + Services.obs.removeObserver(self, "addon-install-blocked"); + Services.obs.removeObserver(self, "addon-install-failed"); + Services.obs.removeObserver(self, "addon-install-complete"); + + AddonManager.removeInstallListener(self); + + Services.wm.removeListener(self); + + AddonManager.getAllInstalls(function(aInstalls) { + is(aInstalls.length, 0, "Should be no active installs at the end of the test"); + aInstalls.forEach(function(aInstall) { + info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state); + aInstall.cancel(); + }); + }); + }); + } + + this.installCount = 0; + this.pendingCount = 0; + this.runningInstalls = []; + }, + + finish: function() { + finish(); + }, + + endTest: function() { + let callback = this.installsCompletedCallback; + let count = this.installCount; + + is(this.runningInstalls.length, 0, "Should be no running installs left"); + this.runningInstalls.forEach(function(aInstall) { + info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state); + }); + + this.installOriginBlockedCallback = null; + this.installBlockedCallback = null; + this.authenticationCallback = null; + this.installConfirmCallback = null; + this.downloadStartedCallback = null; + this.downloadProgressCallback = null; + this.downloadCancelledCallback = null; + this.downloadFailedCallback = null; + this.downloadEndedCallback = null; + this.installStartedCallback = null; + this.installFailedCallback = null; + this.installEndedCallback = null; + this.installsCompletedCallback = null; + this.runningInstalls = null; + + if (callback) + callback(count); + }, + + // Window open handling + windowReady: function(window) { + if (window.document.location.href == XPINSTALL_URL) { + if (this.installBlockedCallback) + ok(false, "Should have been blocked by the whitelist"); + this.pendingCount = window.document.getElementById("itemList").childNodes.length; + + // If there is a confirm callback then its return status determines whether + // to install the items or not. If not the test is over. + let result = true; + if (this.installConfirmCallback) { + result = this.installConfirmCallback(window); + if (result === this.leaveOpen) + return; + } + + if (!result) { + window.document.documentElement.cancelDialog(); + } + else { + // Initially the accept button is disabled on a countdown timer + var button = window.document.documentElement.getButton("accept"); + button.disabled = false; + window.document.documentElement.acceptDialog(); + } + } + else if (window.document.location.href == PROMPT_URL) { + var promptType = window.args.promptType; + switch (promptType) { + case "alert": + case "alertCheck": + case "confirmCheck": + case "confirm": + case "confirmEx": + window.document.documentElement.acceptDialog(); + break; + case "promptUserAndPass": + // This is a login dialog, hopefully an authentication prompt + // for the xpi. + if (this.authenticationCallback) { + var auth = this.authenticationCallback(); + if (auth && auth.length == 2) { + window.document.getElementById("loginTextbox").value = auth[0]; + window.document.getElementById("password1Textbox").value = auth[1]; + window.document.documentElement.acceptDialog(); + } + else { + window.document.documentElement.cancelDialog(); + } + } + else { + window.document.documentElement.cancelDialog(); + } + break; + default: + ok(false, "prompt type " + promptType + " not handled in test."); + break; + } + } + }, + + // Install blocked handling + + installDisabled: function(installInfo) { + ok(!!this.installDisabledCallback, "Installation shouldn't have been disabled"); + if (this.installDisabledCallback) + this.installDisabledCallback(installInfo); + this.endTest(); + }, + + installCancelled: function(installInfo) { + if (this.expectingCancelled) + return; + + ok(!!this.installCancelledCallback, "Installation shouldn't have been cancelled"); + if (this.installCancelledCallback) + this.installCancelledCallback(installInfo); + this.endTest(); + }, + + installOriginBlocked: function(installInfo) { + ok(!!this.installOriginBlockedCallback, "Shouldn't have been blocked"); + if (this.installOriginBlockedCallback) + this.installOriginBlockedCallback(installInfo); + this.endTest(); + }, + + installBlocked: function(installInfo) { + ok(!!this.installBlockedCallback, "Shouldn't have been blocked by the whitelist"); + if (this.installBlockedCallback && this.installBlockedCallback(installInfo)) { + this.installBlockedCallback = null; + installInfo.install(); + } + else { + this.expectingCancelled = true; + installInfo.installs.forEach(function(install) { + install.cancel(); + }); + this.expectingCancelled = false; + this.endTest(); + } + }, + + // nsIWindowMediatorListener + + onWindowTitleChange: function(window, title) { + }, + + onOpenWindow: function(window) { + var domwindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindow); + var self = this; + waitForFocus(function() { + self.windowReady(domwindow); + }, domwindow); + }, + + onCloseWindow: function(window) { + }, + + // Addon Install Listener + + onNewInstall: function(install) { + this.runningInstalls.push(install); + + if (this.finalContentEvent && !this.waitingForEvent) { + this.waitingForEvent = true; + info("Waiting for " + this.finalContentEvent); + let win = gBrowser.contentWindow; + let listener = () => { + info("Saw " + this.finalContentEvent); + win.removeEventListener(this.finalContentEvent, listener, false); + this.waitingForEvent = false; + if (this.pendingCount == 0) + this.endTest(); + } + win.addEventListener(this.finalContentEvent, listener, false); + } + }, + + onDownloadStarted: function(install) { + this.pendingCount++; + if (this.downloadStartedCallback) + this.downloadStartedCallback(install); + }, + + onDownloadProgress: function(install) { + if (this.downloadProgressCallback) + this.downloadProgressCallback(install); + }, + + onDownloadEnded: function(install) { + if (this.downloadEndedCallback) + this.downloadEndedCallback(install); + }, + + onDownloadCancelled: function(install) { + isnot(this.runningInstalls.indexOf(install), -1, + "Should only see cancelations for started installs"); + this.runningInstalls.splice(this.runningInstalls.indexOf(install), 1); + + if (this.downloadCancelledCallback) + this.downloadCancelledCallback(install); + this.checkTestEnded(); + }, + + onDownloadFailed: function(install) { + if (this.downloadFailedCallback) + this.downloadFailedCallback(install); + this.checkTestEnded(); + }, + + onInstallStarted: function(install) { + if (this.installStartedCallback) + this.installStartedCallback(install); + }, + + onInstallEnded: function(install, addon) { + if (this.installEndedCallback) + this.installEndedCallback(install, addon); + this.installCount++; + this.checkTestEnded(); + }, + + onInstallFailed: function(install) { + if (this.installFailedCallback) + this.installFailedCallback(install); + this.checkTestEnded(); + }, + + checkTestEnded: function() { + if (--this.pendingCount == 0 && !this.waitingForEvent) + this.endTest(); + }, + + // nsIObserver + + observe: function(subject, topic, data) { + var installInfo = subject.QueryInterface(Components.interfaces.amIWebInstallInfo); + switch (topic) { + case "addon-install-started": + is(this.runningInstalls.length, installInfo.installs.length, + "Should have seen the expected number of installs started"); + break; + case "addon-install-disabled": + this.installDisabled(installInfo); + break; + case "addon-install-cancelled": + this.installCancelled(installInfo); + break; + case "addon-install-origin-blocked": + this.installOriginBlocked(installInfo); + break; + case "addon-install-blocked": + this.installBlocked(installInfo); + break; + case "addon-install-failed": + installInfo.installs.forEach(function(aInstall) { + isnot(this.runningInstalls.indexOf(aInstall), -1, + "Should only see failures for started installs"); + + ok(aInstall.error != 0 || aInstall.addon.appDisabled, + "Failed installs should have an error or be appDisabled"); + + this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1); + }, this); + break; + case "addon-install-complete": + installInfo.installs.forEach(function(aInstall) { + isnot(this.runningInstalls.indexOf(aInstall), -1, + "Should only see completed events for started installs"); + + is(aInstall.error, 0, "Completed installs should have no error"); + ok(!aInstall.appDisabled, "Completed installs should not be appDisabled"); + + // Complete installs are either in the INSTALLED or CANCELLED state + // since the test may cancel installs the moment they complete. + ok(aInstall.state == AddonManager.STATE_INSTALLED || + aInstall.state == AddonManager.STATE_CANCELLED, + "Completed installs should be in the right state"); + + this.runningInstalls.splice(this.runningInstalls.indexOf(aInstall), 1); + }, this); + break; + } + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsIWindowMediatorListener, + Ci.nsISupports]) +} diff --git a/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi b/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi new file mode 100644 index 000000000..cc40f43c9 Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/installchrome.html b/toolkit/mozapps/extensions/test/xpinstall/installchrome.html new file mode 100644 index 000000000..71c072d3a --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/installchrome.html @@ -0,0 +1,21 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html b/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html new file mode 100644 index 000000000..cd7618cc5 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html @@ -0,0 +1,43 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+

+

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html b/toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html new file mode 100644 index 000000000..2b302642e --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/installtrigger_frame.html @@ -0,0 +1,29 @@ + + + + + + + +InstallTrigger frame tests + + + + + + +

InstallTrigger tests

+

+

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi b/toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi new file mode 100644 index 000000000..11fbe1861 Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/multipackage.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/navigate.html b/toolkit/mozapps/extensions/test/xpinstall/navigate.html new file mode 100644 index 000000000..5a6903eb9 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/navigate.html @@ -0,0 +1,26 @@ + + + + + + + +Navigation tests + + + + +

Test Link

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs b/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs new file mode 100644 index 000000000..d248bfbc7 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs @@ -0,0 +1,45 @@ +// Script has two modes based on the query string. If the mode is "setup" then +// parameters from the query string configure the redirection. If the mode is +// "redirect" then a redirect is returned + +function handleRequest(request, response) +{ + let parts = request.queryString.split("&"); + let settings = {}; + + parts.forEach(function(aString) { + let [k, v] = aString.split("="); + settings[k] = decodeURIComponent(v); + }) + + if (settings.mode == "setup") { + delete settings.mode; + + // Object states must be an nsISupports + var state = { + settings: settings, + QueryInterface: function(aIid) { + if (aIid.equals(Components.interfaces.nsISupports)) + return settings; + throw Components.results.NS_ERROR_NO_INTERFACE; + } + } + state.wrappedJSObject = state; + + setObjectState("xpinstall-redirect-settings", state); + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/plain"); + response.write("Setup complete"); + } + else if (settings.mode == "redirect") { + getObjectState("xpinstall-redirect-settings", function(aObject) { + settings = aObject.wrappedJSObject.settings; + }); + + response.setStatusLine(request.httpVersion, 302, "Found"); + for (var name in settings) { + response.setHeader(name, settings[name]); + } + response.write("Done"); + } +} diff --git a/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi b/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi new file mode 100644 index 000000000..973bc00cb Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi new file mode 100644 index 000000000..90d3a3ce6 Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/signed-no-cn.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi new file mode 100644 index 000000000..19b754038 Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/signed-no-o.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi new file mode 100644 index 000000000..8c951881e Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/signed-tampered.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi new file mode 100644 index 000000000..09789d189 Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/signed-untrusted.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed.xpi new file mode 100644 index 000000000..bd7f78b7c Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/signed.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/signed2.xpi b/toolkit/mozapps/extensions/test/xpinstall/signed2.xpi new file mode 100644 index 000000000..085efbbf7 Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/signed2.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs b/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs new file mode 100644 index 000000000..5f767a8f4 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs @@ -0,0 +1,101 @@ +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/osfile.jsm"); +Cu.import("resource://gre/modules/NetUtil.jsm"); + +const RELATIVE_PATH = "browser/toolkit/mozapps/extensions/test/xpinstall" +const NOTIFICATION_TOPIC = "slowinstall-complete"; + +/** + * Helper function to create a JS object representing the url parameters from + * the request's queryString. + * + * @param aQueryString + * The request's query string. + * @return A JS object representing the url parameters from the request's + * queryString. + */ +function parseQueryString(aQueryString) { + var paramArray = aQueryString.split("&"); + var regex = /^([^=]+)=(.*)$/; + var params = {}; + for (var i = 0, sz = paramArray.length; i < sz; i++) { + var match = regex.exec(paramArray[i]); + if (!match) + throw "Bad parameter in queryString! '" + paramArray[i] + "'"; + params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); + } + + return params; +} + +function handleRequest(aRequest, aResponse) { + let id = +getState("ID"); + setState("ID", "" + (id + 1)); + + function LOG(str) { + dump("slowinstall.sjs[" + id + "]: " + str + "\n"); + } + + aResponse.setStatusLine(aRequest.httpVersion, 200, "OK"); + + var params = { }; + if (aRequest.queryString) + params = parseQueryString(aRequest.queryString); + + if (params.file) { + let xpiFile = ""; + + function complete_download() { + LOG("Completing download"); + downloadPaused = false; + + try { + // Doesn't seem to be a sane way to read using OS.File and write to an + // nsIOutputStream so here we are. + let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + file.initWithPath(xpiFile); + let stream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + stream.init(file, -1, -1, stream.DEFER_OPEN + stream.CLOSE_ON_EOF); + + NetUtil.asyncCopy(stream, aResponse.bodyOutputStream, () => { + LOG("Download complete"); + aResponse.finish(); + }); + } + catch (e) { + LOG("Exception " + e); + } + } + + let waitForComplete = new Promise(resolve => { + function complete() { + Services.obs.removeObserver(complete, NOTIFICATION_TOPIC); + resolve(); + } + + Services.obs.addObserver(complete, NOTIFICATION_TOPIC, false); + }); + + aResponse.processAsync(); + + OS.File.getCurrentDirectory().then(dir => { + xpiFile = OS.Path.join(dir, ...RELATIVE_PATH.split("/"), params.file); + LOG("Starting slow download of " + xpiFile); + + OS.File.stat(xpiFile).then(info => { + aResponse.setHeader("Content-Type", "binary/octet-stream"); + aResponse.setHeader("Content-Length", info.size.toString()); + + LOG("Download paused"); + waitForComplete.then(complete_download); + }); + }); + } + else if (params.continue) { + dump("slowinstall.sjs: Received signal to complete all current downloads.\n"); + Services.obs.notifyObservers(null, NOTIFICATION_TOPIC, null); + } +} diff --git a/toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html b/toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html new file mode 100644 index 000000000..4845a504a --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/startsoftwareupdate.html @@ -0,0 +1,19 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/theme.xpi b/toolkit/mozapps/extensions/test/xpinstall/theme.xpi new file mode 100644 index 000000000..0c94a280b Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/theme.xpi differ diff --git a/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html b/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html new file mode 100644 index 000000000..49fda7dc8 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html @@ -0,0 +1,35 @@ + + + + + + + +InstallTrigger tests + + + +

InstallTrigger tests

+

+

+ + diff --git a/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi b/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi new file mode 100644 index 000000000..51b00475a Binary files /dev/null and b/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-available.png b/toolkit/themes/linux/mozapps/extensions/category-available.png new file mode 100644 index 000000000..689d526c9 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-available.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-dictionaries.png b/toolkit/themes/linux/mozapps/extensions/category-dictionaries.png new file mode 100644 index 000000000..a1e0d5359 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-dictionaries.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-discover.png b/toolkit/themes/linux/mozapps/extensions/category-discover.png new file mode 100644 index 000000000..ccea27524 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-discover.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-experiments.png b/toolkit/themes/linux/mozapps/extensions/category-experiments.png new file mode 100644 index 000000000..a9d00545e Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-experiments.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-plugins.png b/toolkit/themes/linux/mozapps/extensions/category-plugins.png new file mode 100644 index 000000000..b253dd08f Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-plugins.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-recent.png b/toolkit/themes/linux/mozapps/extensions/category-recent.png new file mode 100644 index 000000000..9039b27aa Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-recent.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-search.png b/toolkit/themes/linux/mozapps/extensions/category-search.png new file mode 100644 index 000000000..52e91a7ce Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-search.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/category-service.png b/toolkit/themes/linux/mozapps/extensions/category-service.png new file mode 100644 index 000000000..997c8541c Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/category-service.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/dictionaryGeneric-16.png b/toolkit/themes/linux/mozapps/extensions/dictionaryGeneric-16.png new file mode 100644 index 000000000..08a0447a4 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/dictionaryGeneric-16.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/dictionaryGeneric.png b/toolkit/themes/linux/mozapps/extensions/dictionaryGeneric.png new file mode 100644 index 000000000..a1e0d5359 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/dictionaryGeneric.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/experimentGeneric.png b/toolkit/themes/linux/mozapps/extensions/experimentGeneric.png new file mode 100644 index 000000000..a9d00545e Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/experimentGeneric.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/extensionGeneric-16.png b/toolkit/themes/linux/mozapps/extensions/extensionGeneric-16.png new file mode 100644 index 000000000..b1a2f3652 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/extensionGeneric-16.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/extensionGeneric.png b/toolkit/themes/linux/mozapps/extensions/extensionGeneric.png new file mode 100644 index 000000000..2ae95a5b2 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/extensionGeneric.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/extensions.css b/toolkit/themes/linux/mozapps/extensions/extensions.css new file mode 100644 index 000000000..5c642fbbf --- /dev/null +++ b/toolkit/themes/linux/mozapps/extensions/extensions.css @@ -0,0 +1,956 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@import url("chrome://global/skin/inContentUI.css"); + + +/*** global warnings ***/ + +.global-warning-container { + overflow-x: hidden; +} + +.global-warning { + -moz-box-align: center; + padding: 0 8px; + font-weight: bold; +} + +.global-warning-text { + color: -moz-FieldText; +} + +#addons-page[warning] .global-warning-container { + background-color: rgba(255, 255, 0, 0.1); + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"); + background-repeat: repeat-x; +} + +#detail-view .global-warning { + padding: 4px 12px; + border-bottom: 1px solid ThreeDShadow; + min-height: 41px; +} + +@media (max-width: 600px) { + .global-warning-text { + display: none; + } +} + +/* Plugins aren't yet disabled by safemode (bug 342333), + so don't show that warning when viewing plugins. */ +#addons-page[warning="safemode"] .view-pane[type="plugin"] .global-warning-container, +#addons-page[warning="safemode"] #detail-view[loading="true"] .global-warning-container { + background-color: inherit; + background-image: none; +} + + +/*** notification icons ***/ + +.warning-icon { + list-style-image: url("moz-icon://stock/gtk-dialog-warning?size=menu"); + width: 16px; + height: 16px; + margin: 3px 0; +} + +.error-icon { + list-style-image: url("moz-icon://stock/gtk-dialog-error?size=menu"); + width: 16px; + height: 16px; + margin: 3px 0; +} + +.pending-icon, +.info-icon { + list-style-image: url("moz-icon://stock/gtk-dialog-info?size=menu"); + width: 16px; + height: 16px; + margin: 3px 0; +} + +/*** view alert boxes ***/ + +.alert-container { + -moz-box-align: center; +} + +.alert-spacer-before { + -moz-box-flex: 1; +} + +.alert-spacer-after { + -moz-box-flex: 3; +} + +.alert { + -moz-box-align: center; + padding: 10px; + font-size: 12px; + border: 1px solid ThreeDShadow; + border-radius: 8px; + color: WindowText; + background-color: Window; + background-clip: padding-box; +} + +.alert .alert-title { + font-weight: bold; + font-size: 200%; + margin-bottom: 15px; +} + +.alert button { + margin: 1em 2em; +} + +.loading { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); + padding-left: 20px; + padding-right: 20px; +} + +/*** category selector ***/ + +#categories { + -moz-appearance: none; + border: none; + -moz-margin-end: -1px; + background-color: transparent; + position: relative; + margin-top: 41px; +} + +.category { + -moz-appearance: none; + border-width: 1px; + -moz-border-end-width: 0; + border-style: solid; + border-color: transparent; + padding: 10px 4px; + -moz-box-align: center; + overflow: hidden; + min-height: 0; + color: WindowText; +} + +.category:-moz-locale-dir(ltr) { + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; +} + +.category:-moz-locale-dir(rtl) { + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; +} + +.category[disabled] { + border-top: 0; + border-bottom: 0; + height: 0; + opacity: 0; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category:not([disabled]) { + height: 52px; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category[selected] { + background-color: -moz-Field; + color: -moz-FieldText; + border-color: ThreeDShadow; +} + +.category-name { + font-size: 150%; +} + +/* Maximize the size of the viewport when the window is small */ +@media (max-width: 800px) { + .category-name { + display: none; + } +} + +.category-badge { + background-color: Highlight; + padding: 2px 8px; + margin: 6px 0; + border-radius: 10000px; + color: HighlightText; + font-weight: bold; + text-align: center; +} + +.category-badge[value="0"] { + visibility: hidden; +} + +.category-icon { + width: 32px; + height: 32px; + -moz-margin-start: 6px; +} + +#category-search > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-search.png"); +} +#category-discover > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-discover.png"); +} +#category-locale > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-languages.png"); +} +#category-searchengine > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-searchengines.png"); +} +#category-extension > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-extensions.png"); +} +#category-service > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-service.png"); +} +#category-theme > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-themes.png"); +} +#category-plugin > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-plugins.png"); +} +#category-dictionary > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png"); +} +#category-experiment > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-experiments.png"); +} +#category-availableUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-available.png"); +} +#category-recentUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-recent.png"); +} + + +/*** header ***/ + +#header { + margin-bottom: 18px; +} + +.nav-button { + min-width: 0; +} + +#back-btn:-moz-locale-dir(ltr) { + list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar"); +} + +#forward-btn:-moz-locale-dir(ltr) { + list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar"); +} + +#back-btn:-moz-locale-dir(rtl) { + list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar"); +} + +#forward-btn:-moz-locale-dir(rtl) { + list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar"); +} + +#back-btn[disabled="true"]:-moz-locale-dir(ltr) { + list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar&state=disabled"); +} + +#forward-btn[disabled="true"]:-moz-locale-dir(ltr) { + list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled"); +} + +#back-btn[disabled="true"]:-moz-locale-dir(rtl) { + list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar&state=disabled"); +} + +#forward-btn[disabled="true"]:-moz-locale-dir(rtl) { + list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled"); +} + +#header-utils-btn { + min-width: 4.5em; +} + +#header-utils-btn .toolbarbutton-icon { + list-style-image: url("moz-icon://stock/gtk-preferences?size=toolbar"); +} + +#header-utils-btn:-moz-focusring > .button-box { + border: none; +} + +#header-search { + margin: 0; +} + +@media (max-width: 600px) { + #header-search { + width: 12em; + } +} + +.view-header { + padding: 4px; + margin: 0; + min-height: 41px; + background-color: ThreeDHighlight; + border-bottom: 1px solid ThreeDShadow; +} + + +/*** sorters ***/ + +.sort-controls { + -moz-appearance: none; +} + +.sorter[checkState="1"] .button-icon { + display: -moz-box; + list-style-image: url("moz-icon://stock/gtk-sort-descending?size=16"); +} + +.sorter[checkState="2"] .button-icon { + display: -moz-box; + list-style-image: url("moz-icon://stock/gtk-sort-ascending?size=16"); +} + + +/*** discover view ***/ + +.discover-spacer-before, +.discover-spacer-after { + -moz-box-flex: 1; +} + +#discover-error .alert { + max-width: 45em; + -moz-box-flex: 1; +} + +.discover-logo { + list-style-image: url("chrome://mozapps/skin/extensions/discover-logo.png"); + -moz-margin-end: 15px; +} + +.discover-title { + font-weight: bold; + font-size: 24px; + font-family: MetaWebPro-Book, "Trebuchet MS", sans-serif; + margin: 0 0 15px 0; +} + +.discover-description { + text-align: justify; + margin: 0 0 15px 0; +} + +.discover-footer { + text-align: justify; +} + + +/*** list ***/ + +.list { + -moz-appearance: none; + margin: 0; + border: none; + background-color: transparent; +} + +.addon { + border-bottom: 1px solid ThreeDLightShadow; + padding: 5px; +} + +.addon[selected] .text-link, +.addon[selected] .button-link { + color: inherit; +} + +.details { + cursor: pointer; + margin: 0; + -moz-margin-start: 10px; +} + +.icon-container { + width: 48px; + height: 48px; + margin: 3px 7px; + -moz-box-align: center; + -moz-box-pack: center; +} + +.icon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 48px; + max-height: 48px; +} + +.addon[active="false"] .icon { + filter: grayscale(1); +} + +.addon-view[type="theme"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-view[type="locale"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-view[type="plugin"] .icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-view[type="dictionary"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +.addon-view[type="experiment"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/experimentGeneric.png"); +} + +.name-container { + font-size: 150%; + margin-bottom: 0; + font-weight: bold; + -moz-box-align: end; + -moz-box-flex: 1; +} + +.creator { + font-weight: bold; +} + +.addon-view[active="false"]:not([selected]) { + color: GrayText; +} + +.description-container { + -moz-margin-start: 6px; + -moz-box-align: center; +} + +.description { + margin: 0; +} + +.warning, +.pending, +.error { + -moz-margin-start: 48px; + -moz-box-align: center; +} + +.content-container, +.basicinfo-container { + -moz-box-align: start; +} + +.addon[status="installing"] > .content-container { + -moz-box-align: stretch; +} + +.advancedinfo-container, +.update-info-container { + -moz-box-align: center; +} + +.update-available { + -moz-box-align: end; +} + +.install-status-container { + -moz-box-pack: end; + -moz-box-align: end; +} + +.name-outer-container { + -moz-box-pack: center; +} + +.relnotes-toggle-container, +.icon-outer-container { + -moz-box-pack: start; +} + +.status-container, +.control-container { + -moz-box-pack: end; +} + +.addon-view:not([selected]) .warning { + color: #90792E; +} + +.addon-view:not([selected]) .error { + color: #7C322B; +} + +.addon-view:not([selected]) .pending { + color: #4F7939; +} + +.addon[active="false"] { + background-image: linear-gradient(rgba(135, 135, 135, 0.2), + rgba(135, 135, 135, 0.1)); +} + +.addon-view[notification="warning"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"), + linear-gradient(rgba(255, 255, 0, 0.04), + rgba(255, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[notification="error"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-error.png"), + linear-gradient(rgba(255, 0, 0, 0.04), + rgba(255, 0, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="enable"], +.addon-view[pending="upgrade"], +.addon-view[pending="install"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-positive.png"), + linear-gradient(rgba(0, 255, 0, 0.04), + rgba(0, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="disable"], +.addon-view[pending="uninstall"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-negative.png"), + linear-gradient(rgba(128, 128, 128, 0.04), + rgba(128, 128, 128, 0)); + background-repeat: repeat-x; +} + +.addon .relnotes-container { + -moz-box-align: start; + height: 0; + overflow: hidden; + opacity: 0; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon[show-relnotes] .relnotes-container { + opacity: 1; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon .relnotes-header { + font-weight: bold; + margin: 10px 0; +} + +.addon .relnotes-toggle { + -moz-appearance: none; + border: none; + background: transparent; + font-weight: bold; + cursor: pointer; + list-style-image: url("moz-icon://stock/gtk-go-down?size=16"); +} + +.addon .relnotes-toggle > .button-box > .button-icon { + display: -moz-box; +} + +.addon[show-relnotes] .relnotes-toggle { + list-style-image: url("moz-icon://stock/gtk-go-up?size=16"); +} + + +/*** search view ***/ + +#search-filter { + padding: 5px 20px; + font-size: 120%; + overflow-x: hidden; + border-bottom: 1px solid ThreeDShadow; +} + +#search-filter-label { + font-weight: bold; +} + +#search-allresults-link { + margin-top: 1em; + margin-bottom: 2em; +} + +/*** detail view ***/ + +#detail-view[active="false"] .fade { + opacity: 0.6; +} + +#detail-view .loading { + opacity: 0; +} + +#detail-view[loading-extended] .loading { + -moz-box-align: center; + -moz-box-pack: center; + opacity: 1; + transition-property: opacity; + transition-duration: 1s; +} + +.detail-view-container { + padding: 0 2em 2em 2em; + font-size: 110%; +} + +#detail-notifications { + margin-top: 1em; + margin-bottom: 2em; +} + +#detail-notifications .warning, +#detail-notifications .pending, +#detail-notifications .error { + -moz-margin-start: 0; +} + +#detail-icon-container { + width: 64px; + -moz-margin-end: 10px; +} + +#detail-icon { + max-width: 64px; + max-height: 64px; +} + +#detail-summary { + margin-bottom: 2em; +} + +#detail-name-container { + font-size: 200%; +} + +#detail-screenshot { + -moz-margin-end: 2em; + max-width: 300px; + max-height: 300px; +} + +#detail-screenshot[loading] { + background-image: url("chrome://global/skin/icons/loading_16.png"); + background-position: 50% 50%; + background-repeat: no-repeat; + border: 1px threedshadow solid; + border-radius: 5px; + box-sizing: border-box; +} + +#detail-screenshot[loading="error"] { + background-image: url("chrome://global/skin/media/error.png"); +} + +#detail-desc-container { + margin-bottom: 2em; +} + +#detail-desc, #detail-fulldesc { + -moz-margin-start: 6px; + /* This is necessary to fix layout issues with multi-line descriptions, see + bug 592712*/ + outline: solid transparent; + white-space: pre-wrap; + min-width: 10em; +} + +#detail-fulldesc { + margin-top: 1em; +} + +#detail-contributions { + border-radius: 5px; + border: 1px solid ThreeDShadow; + margin-bottom: 2em; + padding: 1em; + background: ThreeDHighlight; +} + +#detail-contrib-description { + font-style: italic; + margin-bottom: 1em; +} + +#detail-contrib-suggested { + color: GrayText; +} + +#detail-grid { + margin-bottom: 2em; +} + +#detail-grid > columns > column:first-child { + min-width: 15em; + max-width: 25em; +} + +.detail-row[first-row="true"], +.detail-row-complex[first-row="true"], +setting[first-row="true"] { + border-top: none; +} + +.detail-row, +.detail-row-complex, +setting { + border-top: 1px solid ThreeDShadow; + -moz-box-align: center; + min-height: 32px; +} + +#detail-controls { + margin-bottom: 1em; +} + +#detail-view[active="false"]:not([pending]):not([notification]) { + background-image: linear-gradient(rgba(135, 135, 135, 0.1), + rgba(135, 135, 135, 0)); +} + +setting[first-row="true"] { + margin-top: 2em; +} + +setting { + -moz-box-align: start; +} + +.preferences-alignment { + min-height: 32px; + -moz-box-align: center; +} + +.preferences-description { + font-size: 90.9%; + color: graytext; + margin-top: -2px; + -moz-margin-start: 2em; + white-space: pre-wrap; +} + +.preferences-description:empty { + display: none; +} + +menulist { /* Fixes some styling inconsistencies */ + font-size: 100%; + margin: 1px 5px 2px 5px; +} + +colorpicker[type="button"] { /* Fixes some styling inconsistencies */ + height: 29px; + margin: 1px 5px 2px 5px; +} + +setting[type="radio"] > radiogroup { + -moz-box-orient: horizontal; +} + +/*** creator ***/ + +.creator > label { + -moz-margin-start: 0; + -moz-margin-end: 0; +} + +.creator > .text-link { + margin-top: 1px; + margin-bottom: 1px; +} + + +/*** rating ***/ + +.meta-rating { + -moz-margin-end: 0; + vertical-align: text-top; +} + +.meta-rating[showrating="average"] > .star { + list-style-image: url("chrome://mozapps/skin/extensions/rating-not-won.png"); + padding: 0 1px; +} + +.meta-rating[showrating="user"] > .star { + list-style-image: url("chrome://mozapps/skin/extensions/rating-unrated.png"); + padding: 2px 3px; +} + +.meta-rating > .star[on="true"], +.meta-rating[showrating="user"] > .star[hover] { + list-style-image: url("chrome://mozapps/skin/extensions/rating-won.png"); + padding: 0 1px; +} + + +/*** download progress ***/ + +.download-progress { + width: 200px; +} + +.download-progress .start-cap, +.download-progress .end-cap { + display: none; +} + +.download-progress .progress { + padding: 0; + margin: 0; + border: none; +} + +.download-progress .cancel { + -moz-appearance: none; + background-color: ButtonFace; + padding-bottom: 1px; + -moz-padding-start: 2px; + border-width: 1px; + border-style: solid; + border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; + border-radius: 10000px; + min-width: 16px; + width: 16px; + height: 16px; + margin: 3px; +} + +.download-progress .cancel:hover { + background-color: -moz-ButtonHoverFace; +} + +.download-progress .cancel { + list-style-image: url('chrome://mozapps/skin/extensions/cancel.png'); +} + +.download-progress .status-container { + -moz-box-align: center; +} + + +/*** install status ***/ + +.install-status { + -moz-box-align: center; +} + + +/*** check for updates ***/ + +#updates-container { + -moz-box-align: center; +} + +#updates-installed, +#updates-downloaded { + font-weight: bold; +} + +#update-selected { + margin: 12px; +} + + +/*** buttons ***/ + +.addon-control[disabled="true"]:not(.no-auto-hide) { + display: none; +} + +.no-auto-hide .addon-control { + display: block !important; +} + +.addon-control.enable { + list-style-image: url("moz-icon://stock/gtk-yes?size=button"); +} + +.addon-control.disable { + list-style-image: url("moz-icon://stock/gtk-no?size=button"); +} + +.addon-control.remove { + list-style-image: url("moz-icon://stock/gtk-remove?size=button"); +} + +.addon-control.preferences { + list-style-image: url("moz-icon://stock/gtk-preferences?size=button"); +} + +.addon-control.install, +.addon-control.update { + list-style-image: url("moz-icon://stock/gtk-save?size=button"); +} + +.button-link { + -moz-appearance: none; + background: transparent; + border: none; + text-decoration: underline; + color: -moz-nativehyperlinktext; + cursor: pointer; + min-width: 0; + margin: 0 6px; +} + +.button-link:active { + color: -moz-activehyperlinktext; +} + +.header-button .toolbarbutton-text { + display: none; +} + +/*** telemetry experiments ***/ + +#detail-experiment-container { + font-size: 80%; + margin-bottom: 1em; +} + +#detail-experiment-bullet-container, +#detail-experiment-state, +#detail-experiment-time, +.experiment-bullet-container, +.experiment-state, +.experiment-time { + vertical-align: middle; + display: inline-block; +} + +.addon .experiment-bullet, +#detail-experiment-bullet { + fill: rgb(158, 158, 158); +} + +.addon[active="true"] .experiment-bullet, +#detail-view[active="true"] #detail-experiment-bullet { + fill: rgb(106, 201, 20); +} diff --git a/toolkit/themes/linux/mozapps/extensions/localeGeneric.png b/toolkit/themes/linux/mozapps/extensions/localeGeneric.png new file mode 100644 index 000000000..c72115906 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/localeGeneric.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/newaddon.css b/toolkit/themes/linux/mozapps/extensions/newaddon.css new file mode 100644 index 000000000..2e5e25210 --- /dev/null +++ b/toolkit/themes/linux/mozapps/extensions/newaddon.css @@ -0,0 +1,110 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@import url("chrome://global/skin/inContentUI.css"); + +#addon-page { + padding: 0; +} + +#addon-scrollbox { + overflow: auto; + -moz-box-orient: vertical; + -moz-box-flex: 1; +} + +#spacer-start { + -moz-box-flex: 1; +} + +#spacer-end { + -moz-box-flex: 3; +} + +#addon-container { + overflow: visible; + max-width: 600px; + margin: 20px; + padding: 30px 90px; +} + +#addon-info { + -moz-box-align: start; + margin: 25px 10px; +} + +#icon { + -moz-margin-end: 10px; + max-width: 64px; + max-height: 64px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +} + +.addon-info[type="theme"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-info[type="locale"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-info[type="plugin"] #icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-info[type="dictionary"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#name { + font-size: 130%; +} + +#author { + color: GrayText; +} + +#location { + color: GrayText; +} + +#warning { + margin-bottom: 25px; + -moz-box-align: start; +} + +#warning-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.png"); + width: 16px; + height: 15px; + -moz-margin-end: 5px; +} + +#allow { + -moz-margin-start: 84px; + margin-bottom: 20px; +} + +#continuePanel, +#restartPanel { + margin-top: 25px; + -moz-box-pack: end; + -moz-box-align: end; +} + +#continuePanel { + -moz-box-pack: end; +} + +#restartMessage { + text-align: right; +} + +#restartSpacer { + -moz-box-flex: 1; +} + +#later { + color: GrayText; +} diff --git a/toolkit/themes/linux/mozapps/extensions/selectAddons.css b/toolkit/themes/linux/mozapps/extensions/selectAddons.css new file mode 100644 index 000000000..8a94a6c18 --- /dev/null +++ b/toolkit/themes/linux/mozapps/extensions/selectAddons.css @@ -0,0 +1,162 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#view-deck { + background: Window; +} + +.heading { + font-size: 270%; + text-align: center; + margin: 0 100px; +} + +.progress { + margin: 10px 128px; +} + +.progress-label, +#errors-description { + text-align: center; + margin: 0 10px; +} + +#checking-heading, +#update-heading, +#errors-heading { + margin-top: 90px; +} + +#select-heading, +#confirm-heading { + margin-top: 10px; + margin-bottom: 10px; + text-align: center; +} + +#select-description, +#confirm-description { + margin: 10px; +} + +#select-list { + border-top: 1px solid WindowFrame; + background-color: Window; +} + +#select-grid column { + -moz-box-align: center; +} + +#select-grid row { + -moz-box-align: stretch; +} + +#select-grid row:nth-of-type(odd) { + background-color: -moz-oddtreerow; +} + +#select-grid label, +#select-grid checkbox { + margin-top: 0; + margin-bottom: 0; +} + +.select-cell { + -moz-box-align: center; + -moz-box-pack: start; +} + +#select-header .select-cell { + -moz-appearance: treeheadercell; + box-sizing: border-box; +} + +.select-keep { + -moz-box-pack: center; +} + +.select-keep .checkbox-label-box { + display: none; +} + +.select-keep .addon-keep-checkbox:-moz-focusring { + outline: 1px dotted ThreeDDarkShadow; +} + +.select-icon { + width: 20px; +} + +#select-grid separator { + display: none; +} + +.addon-name, +.addon-action-message, +.addon-action-update { + box-sizing: border-box; + margin: 0; + padding-top: 1px; + padding-bottom: 2px; + -moz-padding-start: 6px; + -moz-padding-end: 5px; +} + +.addon:not([active]) .addon-name, +.addon:not([active]) .addon-action-message, +.addon:not([active]) .addon-action-update { + color: GrayText; +} + +.addon-icon { + height: 16px; + width: 16px; + margin: 2px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png"); +} + +.addon-icon[type="theme"] { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric-16.png"); +} + +.addon-icon[type="plugin"] { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png"); +} + +.addon-icon[type="dictionary"] { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric-16.png"); +} + +.action-list { + margin-top: 10px; + -moz-margin-start: 5em; +} + +.action-header { + margin-bottom: 10px; +} + +#confirm .addon { + -moz-margin-start: 3em; + -moz-box-align: center; +} + +.addon:not([active]) .addon-icon, +#disable-list .addon-icon, +#incompatible-list .addon-icon { + filter: grayscale(1); +} + +#footer { + padding: 15px 12px; + border-top: 2px solid; + -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow; +} + +.progress-label, +#footer-label { + font-style: italic; + color: GrayText; +} diff --git a/toolkit/themes/linux/mozapps/extensions/themeGeneric-16.png b/toolkit/themes/linux/mozapps/extensions/themeGeneric-16.png new file mode 100644 index 000000000..019886fea Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/themeGeneric-16.png differ diff --git a/toolkit/themes/linux/mozapps/extensions/themeGeneric.png b/toolkit/themes/linux/mozapps/extensions/themeGeneric.png new file mode 100644 index 000000000..cde1c7834 Binary files /dev/null and b/toolkit/themes/linux/mozapps/extensions/themeGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/about.css b/toolkit/themes/osx/mozapps/extensions/about.css new file mode 100644 index 000000000..cfabd47db --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/about.css @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#genericAbout { + padding: 0px; + min-height: 200px; + max-height: 400px; + width: 30em; +} + +#clientBox { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +.basic-info { + padding: 10px; +} + +#extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 64px; + max-height: 64px; + -moz-margin-end: 6px; +} + +#genericAbout[addontype="theme"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +#genericAbout[addontype="locale"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +#genericAbout[addontype="plugin"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +#genericAbout[addontype="dictionary"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#extensionName { + font-size: 200%; + font-weight: bolder; +} + +#extensionVersion { + font-weight: bold; +} + +#extensionDescription { + margin-top: 4px; +} + +#groove { + margin-top: 8px; +} + +#extensionDetailsBox { + overflow: auto; + min-height: 100px; +} + +.boxIndent { + -moz-margin-start: 18px; +} + +#extensionCreator, .contributor { + margin: 0px; +} + +.sectionTitle { + padding: 2px 0px 3px 0px; + margin-top: 3px; + font-weight: bold; +} diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-error.png b/toolkit/themes/osx/mozapps/extensions/alerticon-error.png new file mode 100644 index 000000000..8740e4911 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-error.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png b/toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png new file mode 100644 index 000000000..2c5f628ab Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-info-negative.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png b/toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png new file mode 100644 index 000000000..a186c6b7a Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-info-positive.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/alerticon-warning.png b/toolkit/themes/osx/mozapps/extensions/alerticon-warning.png new file mode 100644 index 000000000..75ea826f9 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/alerticon-warning.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/blocklist.css b/toolkit/themes/osx/mozapps/extensions/blocklist.css new file mode 100644 index 000000000..b241c9446 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/blocklist.css @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +richlistitem { + padding-top: 6px; + padding-bottom: 6px; + -moz-padding-start: 7px; + -moz-padding-end: 7px; + border-bottom: 1px solid #C0C0C0; +} + +.addon-name-version { + font-size: 110%; +} + +.blockedLabel { + font-weight: bold; + font-style: italic; +} diff --git a/toolkit/themes/osx/mozapps/extensions/cancel.png b/toolkit/themes/osx/mozapps/extensions/cancel.png new file mode 100644 index 000000000..0d98ab235 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/cancel.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-available.png b/toolkit/themes/osx/mozapps/extensions/category-available.png new file mode 100644 index 000000000..d1b737ab0 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-available.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-dictionaries.png b/toolkit/themes/osx/mozapps/extensions/category-dictionaries.png new file mode 100644 index 000000000..54ae4f93f Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-dictionaries.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-discover.png b/toolkit/themes/osx/mozapps/extensions/category-discover.png new file mode 100644 index 000000000..a6f5b49b3 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-discover.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-experiments.png b/toolkit/themes/osx/mozapps/extensions/category-experiments.png new file mode 100644 index 000000000..a9d00545e Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-experiments.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-plugins.png b/toolkit/themes/osx/mozapps/extensions/category-plugins.png new file mode 100644 index 000000000..5c4d8bf47 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-plugins.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-recent.png b/toolkit/themes/osx/mozapps/extensions/category-recent.png new file mode 100644 index 000000000..7ecfc7d4c Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-recent.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-search.png b/toolkit/themes/osx/mozapps/extensions/category-search.png new file mode 100644 index 000000000..52e91a7ce Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-search.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-searchengines.png b/toolkit/themes/osx/mozapps/extensions/category-searchengines.png new file mode 100644 index 000000000..b893cb48a Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-searchengines.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/category-service.png b/toolkit/themes/osx/mozapps/extensions/category-service.png new file mode 100644 index 000000000..997c8541c Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/category-service.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png new file mode 100644 index 000000000..4ad1a1a82 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric-16.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png new file mode 100644 index 000000000..54ae4f93f Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/dictionaryGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/discover-logo.png b/toolkit/themes/osx/mozapps/extensions/discover-logo.png new file mode 100644 index 000000000..cd50735a8 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/discover-logo.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/eula.css b/toolkit/themes/osx/mozapps/extensions/eula.css new file mode 100644 index 000000000..5fb2c52df --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/eula.css @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#icon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 48px; + max-height: 48px; + -moz-margin-end: 6px; +} + +#eula-dialog[addontype="theme"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +#eula-dialog[addontype="locale"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +#eula-dialog[addontype="plugin"] #icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +#eula-dialog[addontype="dictionary"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#heading-container { + -moz-box-align: center; +} + +#heading { + font-size: 120%; +} + +#eula { + -moz-appearance: none; + color: -moz-FieldText; + background-color: -moz-Field; + margin: 1em; + border: 1px solid; + -moz-border-top-colors: ActiveBorder; + -moz-border-right-colors: ActiveBorder; + -moz-border-bottom-colors: ActiveBorder; + -moz-border-left-colors: ActiveBorder; +} + diff --git a/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png b/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png new file mode 100644 index 000000000..a9d00545e Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/experimentGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png b/toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png new file mode 100644 index 000000000..fc6c8a258 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/extensionGeneric-16.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/extensionGeneric.png b/toolkit/themes/osx/mozapps/extensions/extensionGeneric.png new file mode 100644 index 000000000..6a76774c7 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/extensionGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/extensions.css b/toolkit/themes/osx/mozapps/extensions/extensions.css new file mode 100644 index 000000000..9614967a4 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/extensions.css @@ -0,0 +1,1199 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@import url("chrome://global/skin/inContentUI.css"); + +%include ../../global/shared.inc + +@namespace html url("http://www.w3.org/1999/xhtml"); + + +/*** global warnings ***/ + +.global-warning-container { + overflow-x: hidden; +} + +.global-warning { + -moz-box-align: center; + padding: 0 8px; + color: #916D15; + font-weight: bold; +} + +.global-warning, +.global-warning .button-link { + text-shadow: @loweredShadow@; +} + +#addons-page[warning] .global-warning-container { + background-color: rgba(255, 255, 0, 0.1); + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"); + background-repeat: repeat-x; +} + +#detail-view .global-warning { + padding: 4px 12px; + min-height: 31px; + border-bottom: 1px solid rgba(50, 65, 92, 0.4); +} + +@media (max-width: 600px) { + .global-warning-text { + display: none; + } + + .global-warning .warning-icon { + background-color: rgba(255, 255, 255, 0.7); + box-shadow: 0px 0px 2px 4px rgba(255, 255, 255, 0.7); + border-radius: 10px; + } +} + +/*** global informations ***/ +#addons-page .global-info-container { + background-color: #e3e6eb; + border-top-right-radius: 5px; + border-top-left-radius: 5px; +} + +/* Plugins aren't yet disabled by safemode (bug 342333), + so don't show that warning when viewing plugins. */ +#addons-page[warning="safemode"] .view-pane[type="plugin"] .global-warning-container, +#addons-page[warning="safemode"] #detail-view[loading="true"] .global-warning-container { + background-color: inherit; + background-image: none; +} + + +/*** notification icons ***/ + +.warning-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.error-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-error.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.pending-icon, +.info-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-info-positive.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.addon-view[pending="disable"] .pending-icon, +.addon-view[pending="uninstall"] .pending-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-info-negative.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + + +/*** view alert boxes ***/ + +.alert-container { + -moz-box-align: center; +} + +.alert-spacer-before { + -moz-box-flex: 1; +} + +.alert-spacer-after { + -moz-box-flex: 3; +} + +.alert { + -moz-box-align: center; + padding: 10px; + color: #373D48; + font-size: 12px; + border: 1px solid #A8B8D1; + border-radius: 8px; + background-image: linear-gradient(rgba(255, 255, 255, 0.7), rgba(236, 241, 247, 0.7)); + background-clip: padding-box; + box-shadow: 0 -3px 0 rgba(58, 78, 103, 0.05) inset, + 0 3px 0 rgba(175, 195, 220, 0.3); +} + +.alert .alert-title { + font-weight: bold; + font-size: 200%; + margin-bottom: 15px; +} + +.alert button { + margin: 1em 2em; +} + +.loading { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); + padding-left: 20px; + padding-right: 20px; +} + + + +/*** category selector ***/ + +#categories { + -moz-appearance: none; + border: none; + -moz-margin-end: -1px; + background-color: transparent; + position: relative; + margin-top: 31px; +} + +.category { + -moz-appearance: none; + color: #252F3B; + border-width: 1px; + border-style: solid; + border-color: transparent; + padding: 10px 4px; + -moz-box-align: center; + overflow: hidden; + min-height: 0; +} + +.category:-moz-locale-dir(ltr) { + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; +} + +.category:-moz-locale-dir(rtl) { + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; +} + +.category[disabled] { + border-top: 0; + border-bottom: 0; + height: 0; + opacity: 0; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category:not([disabled]) { + height: 52px; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category[selected] { + background-color: rgba(255, 255, 255, 0.35); + color: -moz-dialogtext; + border-color: rgba(50, 65, 92, 0.4); + -moz-border-end-color: #C9CFD7; +} + +.category-name { + font-size: 150%; +} + +/* Maximize the size of the viewport when the window is small */ +@media (max-width: 800px) { + .category-name { + display: none; + } +} + +.category-badge { + background-color: #55D4FF; + padding: 2px 8px; + margin: 6px 0; + border-radius: 10000px; + color: #FFF; + font-weight: bold; + text-align: center; +} + +.category-badge[value="0"] { + visibility: hidden; +} + +.category-icon { + width: 32px; + height: 32px; + -moz-margin-start: 6px; +} + +#category-search > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-search.png"); +} +#category-discover > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-discover.png"); +} +#category-locale > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-languages.png"); +} +#category-searchengine > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-searchengines.png"); +} +#category-extension > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-extensions.png"); +} +#category-service > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-service.png"); +} +#category-theme > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-themes.png"); +} +#category-plugin > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-plugins.png"); +} +#category-dictionary > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png"); +} +#category-experiment > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-experiments.png"); +} +#category-availableUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-available.png"); +} +#category-recentUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-recent.png"); +} + + +/*** header ***/ + +#header { + margin-bottom: 18px; +} + +.nav-button { + list-style-image: url(chrome://mozapps/skin/extensions/navigation.png); +} + +#back-btn:-moz-locale-dir(ltr), +#forward-btn:-moz-locale-dir(rtl) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: none; + -moz-image-region: rect(0, 20px, 20px, 0); + padding-right: 3px; +} + +#back-btn:-moz-locale-dir(rtl), +#forward-btn:-moz-locale-dir(ltr) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + -moz-image-region: rect(0, 40px, 20px, 20px); + padding-left: 3px; +} + +#header-utils-btn { + list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities"); + -moz-margin-end: 18px; +} + +#header-utils-btn > .toolbarbutton-menu-dropmarker { + list-style-image: url("chrome://mozapps/skin/extensions/toolbarbutton-dropmarker.png"); + padding: 0; + -moz-margin-start: 2px; +} + +#header-search { + margin: 0; + -moz-appearance: none; + padding: 3px 5px 2px; + border: 1px solid rgba(60,73,97,0.5); + border-radius: 10000px; + box-shadow: inset 0 1px 1px rgba(0,0,0,0.15), 0 1px rgba(255,255,255,0.25); + background: linear-gradient(rgba(255,255,255,0.2), rgba(255,255,255,0.3)); + background-clip: padding-box; +} + +@media (max-width: 600px) { + #header-search { + width: 12em; + } +} + +#header-search[focused] { + box-shadow: @focusRingShadow@, inset 0 1px 1px rgba(0,0,0,0.15); + border-color: -moz-mac-focusring; +} + +#header-search > .textbox-input-box { + -moz-padding-start: 15px; + background: url("chrome://mozapps/skin/extensions/search.png") left no-repeat; +} + +#header-search > .textbox-input-box:-moz-locale-dir(rtl) { + background-position: right; +} + +#header-search > .textbox-input-box > html|*.textbox-input::-moz-placeholder { + color: #5C6470; + opacity: 1.0; +} + +.view-header { + padding: 4px; + margin: 0; + min-height: 31px; + border-bottom: 1px solid rgba(50, 65, 92, 0.4); + background-image: linear-gradient(rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.05)); +} + + +/*** sorters ***/ + +.sort-controls { + -moz-appearance: none; +} + +.sorter { + -moz-appearance: none; + border: none; + color: #41434B; + background-color: transparent; + border-radius: 10000px; + padding: 0 6px; + margin: 0 6px; + min-width: 12px !important; + -moz-box-direction: reverse; +} + +.sorter[checkState="1"], +.sorter[checkState="2"], +.sorter:active:hover { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; + box-shadow: inset #A3A6AC 0 1px 1px, @loweredShadow@; +} + +.sorter:hover { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; +} + +.sorter[checkState="1"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +.sorter[checkState="2"] { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} + +.sorter .button-icon { + -moz-margin-start: 4px; +} + + +/*** discover view ***/ + +.discover-spacer-before, +.discover-spacer-after { + -moz-box-flex: 1; +} + +#discover-error .alert { + max-width: 45em; + -moz-box-flex: 1; +} + +.discover-logo { + list-style-image: url("chrome://mozapps/skin/extensions/discover-logo.png"); + -moz-margin-end: 15px; +} + +.discover-title { + font-weight: bold; + font-size: 24px; + font-family: MetaWebPro-Book, "Trebuchet MS", sans-serif; + margin: 0 0 15px 0; +} + +.discover-description { + text-align: justify; + margin: 0 0 15px 0; +} + +.discover-footer { + text-align: justify; +} + + +/*** list ***/ + +.list { + -moz-appearance: none; + margin: 0; + border: none; + background-color: transparent; +} + +.addon { + border-bottom: 1px solid #B6B1B9; + padding: 5px; + color: #373D48; +} + +.details { + cursor: pointer; + margin: 0; + -moz-margin-start: 10px; +} + +.icon-container { + width: 48px; + height: 48px; + margin: 3px 7px; + -moz-box-align: center; + -moz-box-pack: center; +} + +.icon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 48px; + max-height: 48px; +} + +.addon[active="false"] .icon { + filter: grayscale(1); +} + +.addon-view[type="theme"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-view[type="locale"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-view[type="plugin"] .icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-view[type="dictionary"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +.addon-view[type="experiment"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/experimentGeneric.png"); +} + +.name-container { + font-size: 150%; + margin-bottom: 0; + font-weight: bold; + color: #000; + text-shadow: @loweredShadow@; + -moz-box-align: end; + -moz-box-flex: 1; +} + +.creator { + font-weight: bold; +} + +.creator .text-link { + color: #0066CC; +} + +.description-container { + margin-top: 8px; + -moz-margin-start: 6px; + -moz-box-align: center; +} + +.description { + margin: 0; +} + +.warning, +.pending, +.error { + -moz-margin-start: 48px; + font-weight: bold; + text-shadow: @loweredShadow@; + -moz-box-align: center; +} + +.content-container, +.basicinfo-container { + -moz-box-align: start; +} + +.addon[status="installing"] > .content-container { + -moz-box-align: stretch; +} + +.update-info-container { + -moz-box-align: center; +} + +.advancedinfo-container, +.update-available { + -moz-box-align: end; +} + +.install-status-container { + -moz-box-pack: end; + -moz-box-align: end; +} + +.name-outer-container { + -moz-box-pack: center; +} + +.relnotes-toggle-container, +.icon-outer-container { + -moz-box-pack: start; +} + +.status-container, +.control-container { + -moz-box-pack: end; +} + +.addon-view .warning { + color: #916D15; +} + +.addon-view .error { + color: #864441; +} + +.addon-view .pending { + color: #1B7123; +} + +.addon-view[pending="disable"] .pending, +.addon-view[pending="uninstall"] .pending { + color: #62666E; +} + +.addon-view[notification="warning"] { + background-image: linear-gradient(rgba(255, 255, 0, 0.2), rgba(255, 255, 0, 0.1)); +} + +.addon-view[notification="error"] { + background-image: linear-gradient(rgba(255, 0, 0, 0.2), rgba(255, 0, 0, 0.1)); +} + +.addon-view[notification="info"] { + background-image: linear-gradient(rgba(0, 0, 255, 0.2), rgba(0, 0, 255, 0.1)); +} + +.addon-view[pending="enable"], +.addon-view[pending="upgrade"], +.addon-view[pending="install"] { + background-image: linear-gradient(rgba(0, 255, 0, 0.2), rgba(0, 255, 0, 0.1)); +} + +.addon-view[pending="disable"], +.addon-view[pending="uninstall"] { + background-image: linear-gradient(rgba(128, 128, 128, 0.2), rgba(128, 128, 128, 0.1)); +} + +.addon .relnotes-container { + -moz-box-align: start; + height: 0; + overflow: hidden; + opacity: 0; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon[show-relnotes] .relnotes-container { + opacity: 1; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon .relnotes-header { + font-weight: bold; + margin: 10px 0; +} + +.addon .relnotes-toggle { + -moz-appearance: none; + border: none; + background: transparent; + font-weight: bold; + -moz-box-direction: reverse; + cursor: pointer; + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +.addon .relnotes-toggle > .button-box > .button-icon { + -moz-padding-start: 4px; +} + +.addon[show-relnotes] .relnotes-toggle { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} + +.addon[active="false"] { + background-color: rgba(135, 135, 135, 0.1); + background-image: linear-gradient(rgba(135, 135, 135, 0), + rgba(135, 135, 135, 0.1)); +} + +.addon-view[active="false"], +.addon-view[active="false"] .name-container { + color: #686A6B; +} + +.addon-view[notification="warning"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"), + linear-gradient(rgba(255, 255, 0, 0.04), + rgba(255, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[notification="error"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-error.png"), + linear-gradient(rgba(255, 0, 0, 0.04), + rgba(255, 0, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="enable"], +.addon-view[pending="upgrade"], +.addon-view[pending="install"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-positive.png"), + linear-gradient(rgba(0, 255, 0, 0.04), + rgba(0, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="disable"], +.addon-view[pending="uninstall"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-negative.png"), + linear-gradient(rgba(128, 128, 128, 0.04), + rgba(128, 128, 128, 0)); + background-repeat: repeat-x; +} + +.addon[selected] { + background-color: rgba(105, 125, 149, 0.39); + color: black; +} + +.addon[selected] .name-container { + text-shadow: @loweredShadow@; +} + +.addon[active="false"][selected] .name-container { + color: #3F3F3F; +} + + +/*** search view ***/ + +#search-filter { + padding: 5px 20px; + font-size: 120%; + overflow-x: hidden; + border-bottom: 1px solid rgba(50, 65, 92, 0.4); +} + +#search-filter-label { + font-weight: bold; + color: #666; +} + +.search-filter-radio { + -moz-appearance: none; + padding: 0 10px; + margin: 0 3px; + border-radius: 10000px; +} + +.search-filter-radio[selected] { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; + box-shadow: inset #A3A6AC 0 1px 1px, @loweredShadow@; +} + +.search-filter-radio:hover { + text-shadow: @loweredShadow@; + background-color: #C0C3CB; +} + +.search-filter-radio .radio-check { + display: none; +} + +.search-filter-radio .radio-icon { + display: none; +} + +#search-allresults-link { + margin-top: 1em; + margin-bottom: 2em; +} + +/*** detail view ***/ + +#detail-view .loading { + opacity: 0; +} + +#detail-view[loading-extended] .loading { + opacity: 1; + transition-property: opacity; + transition-duration: 1s; +} + +.detail-view-container { + padding: 0 2em 2em 2em; + font-size: 110%; +} + +#detail-notifications { + margin-top: 1em; + margin-bottom: 2em; +} + +#detail-notifications .warning, +#detail-notifications .pending, +#detail-notifications .error { + -moz-margin-start: 0; +} + +#detail-icon-container { + width: 64px; + -moz-margin-end: 10px; + margin-top: 6px; +} + +#detail-icon { + max-width: 64px; + max-height: 64px; +} + +#detail-summary { + margin-bottom: 2em; +} + +#detail-name-container { + font-size: 200%; +} + +#detail-screenshot { + -moz-margin-end: 2em; + max-width: 300px; + max-height: 300px; +} + +#detail-screenshot[loading] { + background-image: url("chrome://global/skin/icons/loading_16.png"), + linear-gradient(rgba(255, 255, 255, 0.5), transparent); + background-position: 50% 50%; + background-repeat: no-repeat; + border-radius: 3px; +} + +#detail-screenshot[loading="error"] { + background-image: url("chrome://global/skin/media/error.png"), + linear-gradient(rgba(255, 255, 255, 0.5), transparent); +} + +#detail-desc-container { + margin-bottom: 2em; +} + +#detail-desc, #detail-fulldesc { + -moz-margin-start: 6px; + /* This is necessary to fix layout issues with multi-line descriptions, see + bug 592712*/ + outline: solid transparent; + white-space: pre-wrap; + min-width: 10em; +} + +#detail-fulldesc { + margin-top: 1em; +} + +#detail-contributions { + border-radius: 5px; + border: 1px solid rgba(50, 65, 92, 0.3); + margin-bottom: 2em; + padding: 1em; + background-color: rgba(255, 255, 255, 0.35); +} + +#detail-contrib-description { + font-style: italic; + margin-bottom: 1em; + color: #373D48; +} + +#detail-contrib-suggested { + color: grey; + font-weight: bold; +} + +#detail-contrib-btn { + -moz-appearance: none; + color: #FFF; + border: 1px solid #3A4EEE; + border-radius: 3px; + list-style-image: url("chrome://mozapps/skin/extensions/heart.png"); + background-color: #2F73EF; + background-image: linear-gradient(rgba(251, 252, 253, 0.70), rgba(246, 247, 248, 0.27) 49%, + rgba(231, 232, 233, 0.25) 51%, rgba(225, 226, 229, 0.1)); +} + +#detail-contrib-btn .button-box { + padding: 0 6px 1px 6px; +} + +#detail-contrib-btn .button-icon { + -moz-margin-end: 3px; +} + +#detail-contrib-btn:not(:active):hover { + border-color: #4271FF; + background-color: #0459F7; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1), + 0 0 3.5px hsl(190, 90%, 80%); + transition: background-color .4s ease-in, + border-color .3s ease-in, + box-shadow .3s ease-in; +} + +#detail-contrib-btn:active:hover { + background-color: #8FA1C1; + border-color: rgba(0, 0, 0, 0.65) rgba(0, 0, 0, 0.55) rgba(0, 0, 0, 0.5); + box-shadow: 0 0 6.5px rgba(0, 0, 0, 0.4) inset, + 0 0 2px rgba(0, 0, 0, 0.4) inset; +} + +#detail-grid { + margin-bottom: 2em; +} + +#detail-grid > columns > column:first-child { + min-width: 15em; + max-width: 25em; +} + +.detail-row[first-row="true"], +.detail-row-complex[first-row="true"], +setting[first-row="true"] { + border-top: none; +} + +.detail-row, +.detail-row-complex, +setting { + border-top: 2px solid; + -moz-border-top-colors: rgba(28, 31, 37, 0.2) rgba(255, 255, 255, 0.2); + -moz-box-align: center; + min-height: 30px; +} + +#detail-controls { + margin-bottom: 1em; +} + +#detail-view[active="false"]:not([pending]):not([notification]) { + background-image: linear-gradient(rgba(135, 135, 135, 0.1), + rgba(135, 135, 135, 0)); +} + +setting[first-row="true"] { + margin-top: 2em; +} + +setting { + -moz-box-align: start; +} + +.preferences-alignment { + min-height: 30px; + -moz-box-align: center; +} + +.preferences-description { + font-size: 90.9%; + color: graytext; + margin-top: -2px; + -moz-margin-start: 2em; + white-space: pre-wrap; +} + +.preferences-description:empty { + display: none; +} + +setting[type="radio"] > radiogroup { + -moz-box-orient: horizontal; +} + + +/*** creator ***/ + +.creator > label { + -moz-margin-start: 0; + -moz-margin-end: 0; +} + +.creator > .text-link { + margin-top: 1px; + margin-bottom: 1px; +} + + +/*** rating ***/ + +.meta-rating { + -moz-margin-end: 0; + margin-top: 2px; +} + +.meta-rating > .star { + list-style-image: url("chrome://mozapps/skin/extensions/rating-not-won.png"); + padding: 0 1px; +} + +.meta-rating > .star[on="true"] { + list-style-image: url("chrome://mozapps/skin/extensions/rating-won.png"); +} + + +/*** download progress ***/ + +.download-progress { + background-image: linear-gradient(#DCDEE3, #CBCED6); + border: 1px solid #858898; + border-radius: 3px; + box-shadow: inset #E3E8EC 0 1px 1px, @loweredShadow@; + width: 200px; + height: 21px; + margin: 0 8px; +} + +.download-progress[mode="undetermined"] .progress { + -moz-binding: url("chrome://global/content/bindings/progressmeter.xml#progressmeter-undetermined"); +} + +.download-progress[mode="undetermined"] { + border-color: #2E773A; +} + +.download-progress[mode="undetermined"] .status-container { + padding: 0 2px; +} + +.download-progress .start-cap, +.download-progress[complete] .end-cap, +.download-progress[mode="undetermined"] .end-cap, +.download-progress .progress .progress-bar { + -moz-appearance: none; + background-image: linear-gradient(#6AC47E, #4FAC6A); + margin-top: -1px; + margin-bottom: -1px; + border: 1px solid #2E773A; +} + +.download-progress .start-cap { + -moz-margin-start: -1px; + -moz-border-end-width: 0; +} + +.download-progress .end-cap { + -moz-margin-end: -1px; + -moz-border-start-width: 0px !important; +} + +.download-progress .progress .progress-bar { + border-left-width: 0; + border-right-width: 0; + min-height: 21px; +} + +.download-progress .progress { + -moz-appearance: none; + background-color: transparent; + padding: 0; + margin: 0; + border: none; +} + +.download-progress .start-cap, +.download-progress .end-cap { + width: 4px; +} + +.download-progress .start-cap:-moz-locale-dir(ltr), +.download-progress .end-cap:-moz-locale-dir(rtl) { + border-radius: 3px 0 0 3px; +} + +.download-progress .end-cap:-moz-locale-dir(ltr), +.download-progress .start-cap:-moz-locale-dir(rtl) { + border-radius: 0 3px 3px 0; +} + +.download-progress .cancel { + -moz-appearance: none; + background-color: rgba(255, 255, 255, 0.15); + border: 1px solid rgba(0, 0, 0, 0.4); + padding: 3px; + border-radius: 3px; + min-width: 0; + margin: 3px; +} + +.download-progress .cancel .button-text { + display: none; +} + +.download-progress .cancel .button-icon { + -moz-margin-start: 0; +} + +.download-progress .cancel { + list-style-image: url('chrome://mozapps/skin/extensions/cancel.png'); +} + +.download-progress .status-container { + -moz-box-align: center; +} + +.download-progress .status { + text-shadow: @loweredShadow@; +} + + +/*** install status ***/ + +.install-status { + -moz-box-align: center; +} + + +/*** check for updates ***/ + +#updates-container { + -moz-box-align: center; +} + +#updates-installed, +#updates-downloaded { + color: #3C735C; + font-weight: bold; +} + +#update-selected { + margin: 12px; +} + + +/*** buttons ***/ + +.addon-control[disabled="true"]:not(.no-auto-hide) { + display: none; +} + +.no-auto-hide .addon-control { + display: block !important; +} + +.no-auto-hide > .menulist-dropmarker { + -moz-padding-start: 0px !important; +} + +button.button-link { + -moz-appearance: none; + background: transparent; + border: none; + box-shadow: none; + text-decoration: underline; + color: #0066CC; + cursor: pointer; + min-width: 0; + margin: 0 6px; +} + +.text-link { + color: #3386D5; +} + +.button-link:hover, +.text-link:hover { + color: #3DA1FF; +} + +/* Needed to override normal button style from inContent.css */ +button.button-link:not([disabled="true"]):active:hover { + background: transparent; + border: none; + box-shadow: none; +} + +.header-button { + -moz-appearance: none; + padding: 0 4px; + margin: 0; + height: 22px; + border: 1px solid rgba(60,73,97,0.5); + border-radius: @toolbarbuttonCornerRadius@; + box-shadow: inset 0 1px rgba(255,255,255,0.25), 0 1px rgba(255,255,255,0.25); + background: linear-gradient(rgba(255,255,255,0.45), transparent); + background-clip: padding-box; +} + +.header-button .toolbarbutton-text { + display: none; +} + +.header-button[disabled="true"] .toolbarbutton-icon { + opacity: 0.4; +} + +.header-button:not([disabled="true"]):active:hover, +.header-button[open="true"] { + border-color: rgba(45,54,71,0.7); + box-shadow: inset 0 0 4px rgb(45,54,71), 0 1px rgba(255,255,255,0.25); + background-image: linear-gradient(rgba(45,54,71,0.6), transparent); +} + +/*** telemetry experiments ***/ + +#detail-experiment-container { + font-size: 80%; + margin-bottom: 1em; +} + +#detail-experiment-bullet-container, +#detail-experiment-state, +#detail-experiment-time, +.experiment-bullet-container, +.experiment-state, +.experiment-time { + vertical-align: middle; + display: inline-block; +} + +.addon .experiment-bullet, +#detail-experiment-bullet { + fill: rgb(158, 158, 158); +} + +.addon[active="true"] .experiment-bullet, +#detail-view[active="true"] #detail-experiment-bullet { + fill: rgb(106, 201, 20); +} diff --git a/toolkit/themes/osx/mozapps/extensions/heart.png b/toolkit/themes/osx/mozapps/extensions/heart.png new file mode 100644 index 000000000..655f4c4be Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/heart.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/localeGeneric.png b/toolkit/themes/osx/mozapps/extensions/localeGeneric.png new file mode 100644 index 000000000..4d9ac5ad8 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/localeGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/navigation.png b/toolkit/themes/osx/mozapps/extensions/navigation.png new file mode 100644 index 000000000..ffc40d7e5 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/navigation.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/newaddon.css b/toolkit/themes/osx/mozapps/extensions/newaddon.css new file mode 100644 index 000000000..5bf04fab1 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/newaddon.css @@ -0,0 +1,112 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include ../../global/shared.inc + +@import url("chrome://global/skin/inContentUI.css"); + +#addon-page { + padding: 0; +} + +#addon-scrollbox { + overflow: auto; + -moz-box-orient: vertical; + -moz-box-flex: 1; +} + +#spacer-start { + -moz-box-flex: 1; +} + +#spacer-end { + -moz-box-flex: 3; +} + +#addon-container { + overflow: visible; + max-width: 600px; + margin: 20px; + padding: 30px 90px; +} + +#addon-info { + -moz-box-align: start; + margin: 25px 10px; +} + +#icon { + -moz-margin-end: 10px; + max-width: 64px; + max-height: 64px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +} + +.addon-info[type="theme"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-info[type="locale"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-info[type="plugin"] #icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-info[type="dictionary"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#name { + font-size: 130%; +} + +#author { + color: GrayText; +} + +#location { + color: GrayText; +} + +#warning { + margin-bottom: 25px; + -moz-box-align: start; +} + +#warning-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.png"); + width: 16px; + height: 15px; + -moz-margin-end: 5px; +} + +#allow { + -moz-margin-start: 84px; + margin-bottom: 20px; +} + +#continuePanel, +#restartPanel { + margin-top: 25px; + -moz-box-align: center; + -moz-box-pack: end; +} + +#continuePanel { + -moz-box-pack: end; +} + +#restartMessage { + text-align: right; +} + +#restartSpacer { + -moz-box-flex: 1; +} + +#later { + color: GrayText; +} diff --git a/toolkit/themes/osx/mozapps/extensions/rating-not-won.png b/toolkit/themes/osx/mozapps/extensions/rating-not-won.png new file mode 100644 index 000000000..2761f1925 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/rating-not-won.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/rating-won.png b/toolkit/themes/osx/mozapps/extensions/rating-won.png new file mode 100644 index 000000000..336dd8f6e Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/rating-won.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/search.png b/toolkit/themes/osx/mozapps/extensions/search.png new file mode 100644 index 000000000..93196dbbf Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/search.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/selectAddons.css b/toolkit/themes/osx/mozapps/extensions/selectAddons.css new file mode 100644 index 000000000..8682b04b5 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/selectAddons.css @@ -0,0 +1,163 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%include ../../global/shared.inc + +.heading { + font-size: 270%; + text-align: center; + margin: 0 120px; +} + +.progress { + margin: 10px 128px; +} + +.progress-label, +#errors-description { + text-align: center; + margin: 0 10px; +} + +#checking-heading, +#update-heading, +#errors-heading { + margin-top: 90px; +} + +#select-heading, +#confirm-heading { + margin-top: 10px; + margin-bottom: 10px; + text-align: center; +} + +#select-description, +#confirm-description { + margin: 10px; +} + +#select-list { + border: 1px solid WindowFrame; + background-color: Window; + margin: 10px; +} + +#select-grid column { + -moz-box-align: center; +} + +#select-grid row { + -moz-box-align: stretch; +} + +#select-grid row:nth-of-type(odd) { + background-color: -moz-oddtreerow; +} + +#select-grid label, +#select-grid checkbox { + margin-top: 0; + margin-bottom: 0; +} + +.select-cell { + -moz-box-align: center; + -moz-box-pack: start; + box-sizing: border-box; +} + +#select-header { + background-color: Window !important; +} + +#select-header .select-cell { + -moz-appearance: treeheadercell; + border: 2px solid; + -moz-border-top-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-right-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-bottom-colors: ThreeDDarkShadow ThreeDShadow; + -moz-border-left-colors: ThreeDHighlight ThreeDLightShadow; + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +.select-keep { + -moz-box-pack: center; +} + +.select-icon { + width: 20px; +} + +#select-grid separator { + display: none; +} + +.addon-name, +.addon-action-message, +.addon-action-update { + box-sizing: border-box; + margin: 0; + padding: 2px 6px; +} + +.addon:not([active]) .addon-name, +.addon:not([active]) .addon-action-message, +.addon:not([active]) .addon-action-update { + color: GrayText; +} + +.addon-icon { + height: 16px; + width: 16px; + margin: 2px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png"); +} + +.addon-icon[type="theme"] { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric-16.png"); +} + +.addon-icon[type="plugin"] { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png"); +} + +.addon-icon[type="dictionary"] { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric-16.png"); +} + +.action-list { + margin-top: 10px; + -moz-margin-start: 5em; +} + +.action-header { + margin-bottom: 10px; +} + +#confirm .addon { + -moz-margin-start: 3em; + -moz-box-align: center; +} + +.addon:not([active]) .addon-icon, +#disable-list .addon-icon, +#incompatible-list .addon-icon { + filter: grayscale(1); +} + +#footer { + padding: 15px 12px; + -moz-appearance: statusbar; + -moz-window-dragging: drag; +} + +button { + -moz-appearance: toolbarbutton; + min-height: 22px; + margin: 0 6px; + padding: 0; + text-shadow: @loweredShadow@; +} diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-error.png b/toolkit/themes/osx/mozapps/extensions/stripes-error.png new file mode 100644 index 000000000..1dc2d8504 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-error.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png b/toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png new file mode 100644 index 000000000..901ab1ec2 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-info-negative.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png b/toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png new file mode 100644 index 000000000..370ceec0f Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-info-positive.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/stripes-warning.png b/toolkit/themes/osx/mozapps/extensions/stripes-warning.png new file mode 100644 index 000000000..69463fb1a Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/stripes-warning.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png b/toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png new file mode 100644 index 000000000..190bb30d7 Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/themeGeneric-16.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/themeGeneric.png b/toolkit/themes/osx/mozapps/extensions/themeGeneric.png new file mode 100644 index 000000000..be645f76d Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/themeGeneric.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png b/toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png new file mode 100644 index 000000000..e7674c62a Binary files /dev/null and b/toolkit/themes/osx/mozapps/extensions/toolbarbutton-dropmarker.png differ diff --git a/toolkit/themes/osx/mozapps/extensions/update.css b/toolkit/themes/osx/mozapps/extensions/update.css new file mode 100644 index 000000000..8e9255691 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/update.css @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#alert { + list-style-image: url("chrome://mozapps/skin/update/warning.gif"); +} + +.throbber { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); + width: 16px; + height: 16px; + margin-top: 5px; + margin-bottom: 5px; + -moz-margin-start: 5px; + -moz-margin-end: 2px; +} + +.alertBox { + background-color: InfoBackground; + color: InfoText; + border: 1px outset InfoBackground; + margin-left: 3px; + margin-right: 3px; + padding: 5px; +} diff --git a/toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css b/toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css new file mode 100644 index 000000000..0a1a84b24 --- /dev/null +++ b/toolkit/themes/osx/mozapps/extensions/xpinstallConfirm.css @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#xpinstallheader { + margin-bottom: 2em; +} + +.alert-icon { + width: 48px; + height: 48px; + list-style-image: url("chrome://global/skin/icons/warning-large.png"); + margin-top: 0 !important; + margin-bottom: 6px !important; + -moz-margin-start: 6px !important; + -moz-margin-end: 20px !important; +} + +#itemList { + -moz-appearance: listbox; + margin: 3px 4px 10px 4px; + height: 14em; +} + +#itemWarningIntro { + -moz-margin-start: 8px; +} + +#dialogContentBox { + padding: 5px; +} + +installitem { + padding: 5px 0 5px 5px; + border-bottom: 1px dotted #C0C0C0; + margin-bottom: 5px; +} + +.warning { + font-weight: bold; + font-size: 1.25em; + margin-bottom: 1em; +} + +.xpinstallIconContainer { + width: 32px; + height: 32px; + -moz-margin-end: 5px; +} + +.xpinstallItemName { + font-weight: bold; +} + +.xpinstallItemSigned { + font-style: italic; + font-size: 0.9em; +} + +.xpinstallItemURL { + -moz-appearance: none; + border: none; + background-color: Window; + margin-top: 2px; + margin-bottom: 1px; + -moz-margin-start: 6px; + -moz-margin-end: 5px; +} + +.xpinstallItemIcon { + max-width: 32px; + max-height: 32px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +} + +installitem[type="theme"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +installitem[type="locale"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +installitem[type="plugin"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +installitem[type="dictionary"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} diff --git a/toolkit/themes/shared/extensions/utilities.svg b/toolkit/themes/shared/extensions/utilities.svg new file mode 100644 index 000000000..fd911001b --- /dev/null +++ b/toolkit/themes/shared/extensions/utilities.svg @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/toolkit/themes/windows/mozapps/extensions/about.css b/toolkit/themes/windows/mozapps/extensions/about.css new file mode 100644 index 000000000..7188c11bf --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/about.css @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#genericAbout { + padding: 0px; + min-height: 200px; + max-height: 400px; + width: 30em; +} + +#clientBox { + background-color: -moz-Dialog; + color: -moz-DialogText; +} + +@media (-moz-windows-compositor) { + #genericAbout { + -moz-appearance: -moz-win-glass; + background: transparent; + } + + #clientBox { + -moz-appearance: -moz-win-exclude-glass; + } +} + + +.basic-info { + padding: 10px; +} + +#extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 64px; + max-height: 64px; + -moz-margin-end: 6px; +} + +#genericAbout[addontype="theme"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +#genericAbout[addontype="locale"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +#genericAbout[addontype="plugin"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +#genericAbout[addontype="dictionary"] #extensionIcon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#extensionName { + font-size: 200%; + font-weight: bolder; +} + +#extensionVersion { + font-weight: bold; +} + +#extensionDescription { + margin-top: 4px; +} + +#groove { + margin-top: 8px; +} + +#extensionDetailsBox { + overflow: auto; + min-height: 100px; +} + +.boxIndent { + -moz-margin-start: 18px; +} + +#extensionCreator, .contributor { + margin: 0px; +} + +.sectionTitle { + padding: 2px 0px 3px 0px; + margin-top: 3px; + font-weight: bold; +} + diff --git a/toolkit/themes/windows/mozapps/extensions/alerticon-error.png b/toolkit/themes/windows/mozapps/extensions/alerticon-error.png new file mode 100644 index 000000000..8740e4911 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/alerticon-error.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/alerticon-info-negative.png b/toolkit/themes/windows/mozapps/extensions/alerticon-info-negative.png new file mode 100644 index 000000000..2c5f628ab Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/alerticon-info-negative.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/alerticon-info-positive.png b/toolkit/themes/windows/mozapps/extensions/alerticon-info-positive.png new file mode 100644 index 000000000..a186c6b7a Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/alerticon-info-positive.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/alerticon-warning.png b/toolkit/themes/windows/mozapps/extensions/alerticon-warning.png new file mode 100644 index 000000000..75ea826f9 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/alerticon-warning.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/blocklist.css b/toolkit/themes/windows/mozapps/extensions/blocklist.css new file mode 100644 index 000000000..da92102d0 --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/blocklist.css @@ -0,0 +1,20 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +richlistitem { + padding-top: 6px; + padding-bottom: 6px; + -moz-padding-start: 7px; + -moz-padding-end: 7px; + border-bottom: 1px solid #C0C0C0; +} + +.addonName { + font-weight: bold; +} + +.blockedLabel { + font-weight: bold; + font-style: italic; +} diff --git a/toolkit/themes/windows/mozapps/extensions/cancel.png b/toolkit/themes/windows/mozapps/extensions/cancel.png new file mode 100644 index 000000000..0d98ab235 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/cancel.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-available.png b/toolkit/themes/windows/mozapps/extensions/category-available.png new file mode 100644 index 000000000..9341f2aa7 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-available.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-dictionaries.png b/toolkit/themes/windows/mozapps/extensions/category-dictionaries.png new file mode 100644 index 000000000..b26bb7100 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-dictionaries.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-discover.png b/toolkit/themes/windows/mozapps/extensions/category-discover.png new file mode 100644 index 000000000..af954a613 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-discover.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-experiments.png b/toolkit/themes/windows/mozapps/extensions/category-experiments.png new file mode 100644 index 000000000..a9d00545e Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-experiments.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-plugins.png b/toolkit/themes/windows/mozapps/extensions/category-plugins.png new file mode 100644 index 000000000..1fcbf154e Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-plugins.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-recent.png b/toolkit/themes/windows/mozapps/extensions/category-recent.png new file mode 100644 index 000000000..d65158646 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-recent.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-search.png b/toolkit/themes/windows/mozapps/extensions/category-search.png new file mode 100644 index 000000000..52e91a7ce Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-search.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-searchengines.png b/toolkit/themes/windows/mozapps/extensions/category-searchengines.png new file mode 100644 index 000000000..b893cb48a Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-searchengines.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/category-service.png b/toolkit/themes/windows/mozapps/extensions/category-service.png new file mode 100644 index 000000000..997c8541c Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/category-service.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/dictionaryGeneric-16.png b/toolkit/themes/windows/mozapps/extensions/dictionaryGeneric-16.png new file mode 100644 index 000000000..37e2a5e4c Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/dictionaryGeneric-16.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/dictionaryGeneric.png b/toolkit/themes/windows/mozapps/extensions/dictionaryGeneric.png new file mode 100644 index 000000000..b26bb7100 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/dictionaryGeneric.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/discover-logo.png b/toolkit/themes/windows/mozapps/extensions/discover-logo.png new file mode 100644 index 000000000..cd50735a8 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/discover-logo.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/eula.css b/toolkit/themes/windows/mozapps/extensions/eula.css new file mode 100644 index 000000000..5fb2c52df --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/eula.css @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#icon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 48px; + max-height: 48px; + -moz-margin-end: 6px; +} + +#eula-dialog[addontype="theme"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +#eula-dialog[addontype="locale"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +#eula-dialog[addontype="plugin"] #icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +#eula-dialog[addontype="dictionary"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#heading-container { + -moz-box-align: center; +} + +#heading { + font-size: 120%; +} + +#eula { + -moz-appearance: none; + color: -moz-FieldText; + background-color: -moz-Field; + margin: 1em; + border: 1px solid; + -moz-border-top-colors: ActiveBorder; + -moz-border-right-colors: ActiveBorder; + -moz-border-bottom-colors: ActiveBorder; + -moz-border-left-colors: ActiveBorder; +} + diff --git a/toolkit/themes/windows/mozapps/extensions/experimentGeneric.png b/toolkit/themes/windows/mozapps/extensions/experimentGeneric.png new file mode 100644 index 000000000..a9d00545e Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/experimentGeneric.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/extensionGeneric-16.png b/toolkit/themes/windows/mozapps/extensions/extensionGeneric-16.png new file mode 100644 index 000000000..0ddee4c9b Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/extensionGeneric-16.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/extensionGeneric-48.png b/toolkit/themes/windows/mozapps/extensions/extensionGeneric-48.png new file mode 100644 index 000000000..27418fba8 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/extensionGeneric-48.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/extensionGeneric.png b/toolkit/themes/windows/mozapps/extensions/extensionGeneric.png new file mode 100644 index 000000000..5a3162363 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/extensionGeneric.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/extensions.css b/toolkit/themes/windows/mozapps/extensions/extensions.css new file mode 100644 index 000000000..f350f7ca6 --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/extensions.css @@ -0,0 +1,1234 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@import url("chrome://global/skin/inContentUI.css"); + + +.nav-button { + list-style-image: url(chrome://mozapps/skin/extensions/navigation.png); +} + +#forward-btn { + -moz-border-start: none; +} + +#back-btn:-moz-locale-dir(ltr), +#forward-btn:-moz-locale-dir(rtl) { + -moz-image-region: rect(0, 18px, 18px, 0); + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +#back-btn:-moz-locale-dir(rtl), +#forward-btn:-moz-locale-dir(ltr) { + -moz-image-region: rect(0, 36px, 18px, 18px); + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + + +/*** global warnings ***/ + +.global-warning-container { + overflow-x: hidden; +} + +.global-warning { + -moz-box-align: center; + padding: 0 8px; + color: #916D15; + font-weight: bold; +} + +#addons-page[warning] .global-warning-container { + background-color: rgba(255, 255, 0, 0.1); + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"); + background-repeat: repeat-x; +} + +#detail-view .global-warning { + padding: 4px 12px; + border-bottom: 1px solid #CAD4E0; +} + +@media (max-width: 600px) { + .global-warning-text { + display: none; + } + + .global-warning .warning-icon { + background-color: #FFF; + box-shadow: 0px 0px 2px 5px #FFF; + border-radius: 10px; + } +} + +/*** global informations ***/ +#addons-page .global-info-container { + background-color: #f3f7fb; + border-top-right-radius: 5px; + border-top-left-radius: 5px; +} + +/* Plugins aren't yet disabled by safemode (bug 342333), + so don't show that warning when viewing plugins. */ +#addons-page[warning="safemode"] .view-pane[type="plugin"] .global-warning-container, +#addons-page[warning="safemode"] #detail-view[loading="true"] .global-warning-container { + background-color: inherit; + background-image: none; +} + + +/*** notification icons ***/ + +.warning-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.error-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-error.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.pending-icon, +.info-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-info-positive.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + +.addon-view[pending="disable"] .pending-icon, +.addon-view[pending="uninstall"] .pending-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-info-negative.png"); + width: 16px; + height: 15px; + margin: 3px 0; +} + + +/*** view alert boxes ***/ + +.alert-container { + -moz-box-align: center; +} + +.alert-spacer-before { + -moz-box-flex: 1; +} + +.alert-spacer-after { + -moz-box-flex: 3; +} + +.alert { + -moz-box-align: center; + padding: 10px; + color: #373D48; + border: 1px solid #A8B8D1; + border-radius: 8px; + background-image: linear-gradient(#FFF, #ECF1F7); + background-clip: padding-box; + box-shadow: 2px 2px 4px #999; +} + +.alert .alert-title { + font-weight: bold; + font-size: 200%; + margin-bottom: 15px; +} + +.alert button { + margin: 1em 2em; +} + +.loading { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); + padding-left: 20px; + padding-right: 20px; +} + + +/*** category selector ***/ + +#categories { + -moz-appearance: none; + border: none; + -moz-margin-end: -1px; + background-color: transparent; + position: relative; + margin-top: 31px; +} + +.category { + -moz-appearance: none; + background-color: transparent; + color: #252F3B; + min-height: 0; + padding: 10px 4px; + border-width: 1px; + border-style: solid; + border-color: transparent; + -moz-box-align: center; + overflow: hidden; +} + +%ifdef XP_WIN +@media (-moz-os-version: windows-vista), + (-moz-os-version: windows-win7) { +%endif + .category:-moz-locale-dir(ltr) { + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + } + + .category:-moz-locale-dir(rtl) { + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + } +%ifdef XP_WIN +} +%endif + +.category[disabled] { + border-top: 0; + border-bottom: 0; + height: 0; + opacity: 0; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category:not([disabled]) { + height: 52px; + transition-property: height, opacity; + transition-duration: 1s, 0.8s; +} + +.category[selected] { + background-color: rgba(255, 255, 255, 0.4); + color: #252F3B; + border-color: #C3CEDF; + -moz-border-end-color: #E2E9F2; +} + +.category-name { + font-size: 150%; +} + +/* Maximize the size of the viewport when the window is small */ +@media (max-width: 800px) { + .category-name { + display: none; + } +} + +.category-badge { + background-color: #55D4FF; + padding: 2px 8px; + margin: 6px 0; + border-radius: 10000px; + color: #FFF; + font-weight: bold; + text-align: center; +} + +.category-badge[value="0"] { + visibility: hidden; +} + +.category-icon { + width: 32px; + height: 32px; + -moz-margin-start: 6px; +} + +#category-search > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-search.png"); +} +#category-discover > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-discover.png"); +} +#category-locale > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-languages.png"); +} +#category-searchengine > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-searchengines.png"); +} +#category-extension > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-extensions.png"); +} +#category-service > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-service.png"); +} +#category-theme > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-themes.png"); +} +#category-plugin > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-plugins.png"); +} +#category-dictionary > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-dictionaries.png"); +} +#category-experiment > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-experiments.png"); +} +#category-availableUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-available.png"); +} +#category-recentUpdates > .category-icon { + list-style-image: url("chrome://mozapps/skin/extensions/category-recent.png"); +} + + +/*** header ***/ + +#header { + margin-bottom: 18px; +} + +#header-search { + margin: 0; +} + +@media (max-width: 600px) { + #header-search { + width: 12em; + } +} + +@media (-moz-windows-default-theme) { + #header-search { + -moz-appearance: none; + border: 1px solid rgba(0, 0, 0, 0.32); + padding-bottom: 2px; + background-color: rgba(255, 255, 255, 0.4); + } + +%ifdef XP_WIN +@media (-moz-os-version: windows-vista), + (-moz-os-version: windows-win7) { +%endif + #header-search { + border-radius: 2.5px; + } +%ifdef XP_WIN +} +%endif + + #header-search:hover { + background-color: rgba(255, 255, 255, .75); + } + + #header-search[focused] { + background-color: white; + } +} + +#header-utils-btn { + list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities"); + -moz-margin-end: 16px; +} + +@media not all and (-moz-windows-default-theme) { + #header-utils-btn { + list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities-native"); + } +} + +.view-header { + background-color: rgba(251, 252, 253, 0.25); + padding: 4px; + margin: 0; + min-height: 31px; + border-bottom: 1px solid #CAD4E0; +} + + +/*** sorters ***/ + +.sort-controls { + -moz-appearance: none; +} + +.sorter { + -moz-appearance: none; + border: none; + background-color: transparent; + color: #536680; + border-radius: 10000px; + padding: 0 6px; + margin: 0 6px; + min-width: 12px !important; + -moz-box-direction: reverse; +} + +.sorter .button-box { + padding-top: 0; + padding-bottom: 0; +} + +.sorter[checkState="1"], +.sorter[checkState="2"] { + background-color: rgba(194, 200, 206, 0.4); + box-shadow: 1px 1px 2px #B6BBC4 inset; +} + +.sorter[checkState="1"] { + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +.sorter[checkState="2"] { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} + +.sorter .button-icon { + -moz-margin-start: 4px; +} + + +/*** discover view ***/ + +.discover-spacer-before, +.discover-spacer-after { + -moz-box-flex: 1; +} + +#discover-error .alert { + max-width: 45em; + -moz-box-flex: 1; +} + +.discover-logo { + list-style-image: url("chrome://mozapps/skin/extensions/discover-logo.png"); + -moz-margin-end: 15px; +} + +.discover-title { + font-weight: bold; + font-size: 24px; + font-family: MetaWebPro-Book, "Trebuchet MS", sans-serif; + margin: 0 0 15px 0; +} + +.discover-description { + text-align: justify; + margin: 0 0 15px 0; +} + +.discover-footer { + text-align: justify; +} + + +/*** list ***/ + +.list { + -moz-appearance: none; + margin: 0; + border: none; + background-color: transparent; +} + +.addon { + color: black; + border-top: 2px solid; + -moz-border-top-colors: rgba(0, 0, 0, 0.1) rgba(255, 255, 255, 0.1); + border-bottom: 1px solid; + -moz-border-bottom-colors: rgba(255, 255, 255, 0.1); + padding: 5px; + background-origin: border-box; +} + +.view-pane:not(#search-view) .addon:first-of-type, +#search-view .addon[first] { + border-top-width: 1px; + -moz-border-top-colors: rgba(255, 255, 255, 0.1); +} + +.view-pane:not(#search-view) .addon:last-of-type, +#search-view .addon[last] { + border-bottom-width: 2px; + -moz-border-bottom-colors: rgba(0, 0, 0, 0.1) rgba(255, 255, 255, 0.1); +} + +.details { + cursor: pointer; + margin: 0; + -moz-margin-start: 10px; +} + +.icon-container { + width: 48px; + height: 48px; + margin: 3px 7px; + -moz-box-align: center; + -moz-box-pack: center; +} + +.icon { + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); + max-width: 48px; + max-height: 48px; +} + +.addon[active="false"] .icon { + filter: grayscale(1); +} + + +.addon-view[type="theme"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-view[type="locale"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-view[type="plugin"] .icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-view[type="dictionary"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +.addon-view[type="experiment"] .icon { + list-style-image: url("chrome://mozapps/skin/extensions/experimentGeneric.png"); +} + +.name-container { + font-size: 150%; + font-weight: bold; + color: #3F3F3F; + margin-bottom: 0; + -moz-box-align: end; + -moz-box-flex: 1; +} + +.creator { + font-weight: bold; +} + +.creator .text-link { + color: #0066CC; +} + +.description-container { + -moz-margin-start: 6px; + -moz-box-align: center; +} + +.description { + margin: 0; +} + +.warning, +.pending, +.error { + -moz-margin-start: 48px; + font-weight: bold; + -moz-box-align: center; +} + +.content-container, +.basicinfo-container { + -moz-box-align: start; +} + +.addon[status="installing"] > .content-container { + -moz-box-align: stretch; +} + +.advancedinfo-container, +.update-info-container { + -moz-box-align: center; +} + +.update-available { + -moz-box-align: end; +} + +.install-status-container { + -moz-box-pack: end; + -moz-box-align: end; +} + +.name-outer-container { + -moz-box-pack: center; +} + +.relnotes-toggle-container, +.icon-outer-container { + -moz-box-pack: start; +} + +.status-container, +.control-container { + -moz-box-pack: end; +} + +.addon-view .warning { + color: #916D15; +} + +.addon-view .error { + color: #864441; +} + +.addon-view .pending { + color: #1B7123; +} + +.addon-view[pending="disable"] .pending, +.addon-view[pending="uninstall"] .pending { + color: #62666E; +} + +.addon .relnotes-container { + -moz-box-align: start; + -moz-margin-start: 6px; + height: 0; + overflow: hidden; + opacity: 0; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon[show-relnotes] .relnotes-container { + opacity: 1; + transition-property: height, opacity; + transition-duration: 0.5s, 0.5s; +} + +.addon .relnotes-header { + font-weight: bold; + margin: 10px 0; +} + +.addon .relnotes-toggle { + -moz-appearance: none; + border: none; + background: transparent; + font-weight: bold; + -moz-box-direction: reverse; + cursor: pointer; + list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); +} + +.addon .relnotes-toggle > .button-box > .button-icon { + -moz-padding-start: 4px; +} + +.addon[show-relnotes] .relnotes-toggle { + list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); +} + +.addon[active="false"] { + background-color: rgba(135, 135, 135, 0.1); + background-image: linear-gradient(rgba(135, 135, 135, 0), + rgba(135, 135, 135, 0.1)); +} + +.addon-view[active="false"], +.addon-view[active="false"] .name-container { + color: #888A8B; +} + +.addon-view[notification="warning"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-warning.png"), + linear-gradient(rgba(255, 255, 0, 0.04), + rgba(255, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[notification="error"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-error.png"), + linear-gradient(rgba(255, 0, 0, 0.04), + rgba(255, 0, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="enable"], +.addon-view[pending="upgrade"], +.addon-view[pending="install"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-positive.png"), + linear-gradient(rgba(0, 255, 0, 0.04), + rgba(0, 255, 0, 0)); + background-repeat: repeat-x; +} + +.addon-view[pending="disable"], +.addon-view[pending="uninstall"] { + background-image: url("chrome://mozapps/skin/extensions/stripes-info-negative.png"), + linear-gradient(rgba(128, 128, 128, 0.04), + rgba(128, 128, 128, 0)); + background-repeat: repeat-x; +} + +.addon[selected] { + background-color: rgba(148, 172, 204, 0.39); + color: black; +} + +.addon[active="false"][selected] .name-container { + color: #3F3F3F; +} + + +/*** item - uninstalled ***/ + +.addon[status="uninstalled"] { + border: none; +} + +.addon[status="uninstalled"] > .container { + -moz-box-align: center; + padding: 4px 20px; + background-color: #FDFFA8; + border-radius: 8px; + font-size: 120%; +} + +.addon[status="uninstalled"][selected] { + background-color: transparent; +} + + + +/*** search view ***/ + +#search-filter { + padding: 5px 20px; + font-size: 120%; + border-bottom: 1px solid #CAD4E0; + overflow-x: hidden; +} + +#search-filter-label { + font-weight: bold; + color: grey; +} + +.search-filter-radio { + -moz-appearance: none; + padding: 0 6px; + margin: 0 3px; + border-radius: 10000px; +} + +.search-filter-radio[selected] { + background-color: grey; + color: white; +} + +.search-filter-radio .radio-check-box1 { + display: none; +} + +.search-filter-radio .radio-icon { + display: none; +} + +#search-allresults-link { + margin-top: 1em; + margin-bottom: 2em; +} + +/*** detail view ***/ + +#detail-view .loading { + opacity: 0; +} + +#detail-view[loading-extended] .loading { + opacity: 1; + transition-property: opacity; + transition-duration: 1s; +} + +.detail-view-container { + padding: 0 2em 2em 2em; + font-size: 110%; +} + +#detail-notifications { + margin-top: 1em; + margin-bottom: 2em; +} + +#detail-notifications .warning, +#detail-notifications .pending, +#detail-notifications .error { + -moz-margin-start: 0; +} + +#detail-icon-container { + width: 64px; + -moz-margin-end: 10px; + margin-top: 6px; +} + +#detail-icon { + max-width: 64px; + max-height: 64px; +} + +#detail-summary { + margin-bottom: 2em; +} + +#detail-name-container { + font-size: 200%; +} + +#detail-screenshot { + -moz-margin-end: 2em; + max-width: 300px; + max-height: 300px; +} + +#detail-screenshot[loading] { + background-image: url("chrome://global/skin/icons/loading_16.png"), + linear-gradient(rgba(255, 255, 255, 0.5), transparent); + background-position: 50% 50%; + background-repeat: no-repeat; + border-radius: 3px; +} + +#detail-screenshot[loading="error"] { + background-image: url("chrome://global/skin/media/error.png"), + linear-gradient(rgba(255, 255, 255, 0.5), transparent); +} + +#detail-desc-container { + margin-bottom: 2em; +} + +#detail-desc, #detail-fulldesc { + -moz-margin-start: 6px; + /* This is necessary to fix layout issues with multi-line descriptions, see + bug 592712*/ + outline: solid transparent; + white-space: pre-wrap; + min-width: 10em; +} + +#detail-fulldesc { + margin-top: 1em; +} + +#detail-contributions { + border-radius: 5px; + border: 1px solid #D2DBE8; + margin-bottom: 2em; + padding: 1em; + background-color: #F3F7FB; +} + +#detail-contrib-description { + font-style: italic; + margin-bottom: 1em; + color: #373D48; +} + +#detail-contrib-suggested { + color: grey; + font-weight: bold; +} + +#detail-contrib-btn { + -moz-appearance: none; + color: #FFF; + border: 1px solid #3A4EEE; + border-radius: 3px; + list-style-image: url("chrome://mozapps/skin/extensions/heart.png"); + background-color: #2F73EF; + background-image: linear-gradient(rgba(251, 252, 253, 0.70), rgba(246, 247, 248, 0.27) 49%, + rgba(231, 232, 233, 0.25) 51%, rgba(225, 226, 229, 0.1)); +} + +#detail-contrib-btn .button-box { + padding: 0 6px 1px 6px; +} + +#detail-contrib-btn .button-icon { + -moz-margin-end: 3px; +} + +#detail-contrib-btn:not(:active):hover { + border-color: #4271FF; + background-color: #0459F7; + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1), + 0 0 3.5px hsl(190, 90%, 80%); + transition: background-color .4s ease-in, + border-color .3s ease-in, + box-shadow .3s ease-in; +} + +#detail-contrib-btn:active:hover { + background-color: #8FA1C1; + border-color: rgba(0, 0, 0, 0.65) rgba(0, 0, 0, 0.55) rgba(0, 0, 0, 0.5); + box-shadow: 0 0 6.5px rgba(0, 0, 0, 0.4) inset, + 0 0 2px rgba(0, 0, 0, 0.4) inset, + 0 1px 0 rgba(255, 255, 255, 0.4); +} + +#detail-grid { + margin-bottom: 2em; +} + +#detail-grid > columns > column:first-child { + min-width: 15em; + max-width: 25em; +} + +.detail-row[first-row="true"], +.detail-row-complex[first-row="true"], +setting[first-row="true"] { + border-top: none; +} + +.detail-row, +.detail-row-complex, +setting { + border-top: 2px solid; + -moz-border-top-colors: rgba(28, 31, 37, 0.1) rgba(255, 255, 255, 0.1); + -moz-box-align: center; + min-height: 30px; +} + +#detail-controls { + margin-bottom: 1em; +} + +#detail-view[active="false"]:not([pending]):not([notification]) { + background-image: linear-gradient(rgba(135, 135, 135, 0.1), + rgba(135, 135, 135, 0)); +} + +setting[first-row="true"] { + margin-top: 2em; +} + +setting { + -moz-box-align: start; +} + +.preferences-alignment { + min-height: 30px; + -moz-box-align: center; +} + +.preferences-description { + font-size: 90.9%; + color: graytext; + margin-top: -2px; + -moz-margin-start: 2em; + white-space: pre-wrap; +} + +.preferences-description:empty { + display: none; +} + +setting[type="radio"] > radiogroup { + -moz-box-orient: horizontal; +} + +menulist { /* Fixes some styling inconsistencies */ + margin: 1px 5px 2px 5px; +} + +/*** creator ***/ + +.creator > label { + -moz-margin-start: 0; + -moz-margin-end: 0; +} + +.creator > .text-link { + margin-top: 1px; + margin-bottom: 1px; +} + + +/*** rating ***/ + +.meta-rating { + -moz-margin-end: 0; + padding-top: 2px; +} + +.meta-rating > .star { + list-style-image: url("chrome://mozapps/skin/extensions/rating-not-won.png"); + padding: 0 1px; +} + +.meta-rating > .star[on="true"] { + list-style-image: url("chrome://mozapps/skin/extensions/rating-won.png"); +} + + +/*** download progress ***/ + +.download-progress { + background-color: rgba(151,152,153,.05); + background-image: linear-gradient(rgba(251, 252, 253, 0.95), rgba(246, 247, 248, 0.47) 49%, + rgba(231, 232, 233, 0.45) 51%, rgba(225, 226, 229, 0.3)); + background-clip: padding-box; + border-radius: 3px; + border: 1px solid; + border-color: rgba(0, 0, 0, 0.12) rgba(0, 0, 0, 0.19) rgba(0, 0, 0, 0.38); + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.3) inset, + 0 0 0 2px rgba(255, 255, 255, 0.1) inset; + width: 200px; + height: 21px; + margin: 0 8px; +} + +.download-progress[mode="undetermined"] { + border-color: #358942 #317F3D #2E773A; +} + +.download-progress[mode="undetermined"] .status-container { + padding: 0 2px; +} + +.download-progress .start-cap, +.download-progress[complete] .end-cap, +.download-progress[mode="undetermined"] .end-cap, +.download-progress .progress .progress-bar { + -moz-appearance: none; + background-image: linear-gradient(#92DDA0, #6FC483 49%, #5EB272 51%, #80CE91); + margin-top: -1px; + margin-bottom: -1px; + border: 1px solid; + border-color: #358942 #317F3D #2E773A; +} + +.download-progress .start-cap { + -moz-margin-start: -1px; + -moz-border-end-width: 0; +} + +.download-progress .end-cap { + -moz-margin-end: -1px; + -moz-border-start-width: 0px !important; +} + +.download-progress .progress .progress-bar { + border-left-width: 0; + border-right-width: 0; + min-height: 21px; +} + +.download-progress .progress { + -moz-appearance: none; + background-color: transparent; + padding: 0; + margin: 0; + border: none; +} + +.download-progress .start-cap, +.download-progress .end-cap { + width: 4px; +} + +.download-progress .start-cap:-moz-locale-dir(ltr), +.download-progress .end-cap:-moz-locale-dir(rtl) { + border-radius: 3px 0 0 3px; +} + +.download-progress .end-cap:-moz-locale-dir(ltr), +.download-progress .start-cap:-moz-locale-dir(rtl) { + border-radius: 0 3px 3px 0; +} + +.download-progress .cancel { + -moz-appearance: none; + background-color: rgba(255, 255, 255, 0.4); + border: 1px solid rgba(0, 0, 0, 0.4); + padding: 3px; + border-radius: 3px; + min-width: 0; + margin: 3px; +} + +.download-progress .cancel:hover { + background-color: rgba(255, 255, 255, 0.6); + border: 1px solid rgba(0, 0, 0, 0.8); +} + +.download-progress .cancel:active:hover { + box-shadow: inset rgba(0, 0, 0, 0.5) 1px 1px 2px; +} + +.download-progress .cancel .button-box { + padding: 0; + border: none; +} + +.download-progress .cancel .button-text { + display: none; +} + +.download-progress .cancel .button-icon { + -moz-margin-start: 0; +} + +.download-progress .cancel { + list-style-image: url('chrome://mozapps/skin/extensions/cancel.png'); +} + +.download-progress .status-container { + -moz-box-align: center; +} + +.download-progress .status { + text-shadow: #FFF 0 0 2px; +} + +/*** install status ***/ + +.install-status { + -moz-box-align: center; +} + + +/*** check for updates ***/ + +#updates-container { + -moz-box-align: center; +} + +#updates-container .button-link { + font-weight: bold; +} + +#updates-installed, +#updates-downloaded { + color: #00BB00; + font-weight: bold; +} + +#update-selected { + margin: 12px; +} + + +/*** buttons ***/ + +.addon-control[disabled="true"]:not(.no-auto-hide) { + display: none; +} + +.no-auto-hide .addon-control { + display: block !important; +} + +button.button-link { + -moz-appearance: none; + background: transparent; + border: none; + box-shadow: none; + text-decoration: underline; + color: #0066CC; + cursor: pointer; + min-width: 0; + margin: 0 6px; +} + +.text-link { + color: #3386D5; +} + +.button-link:hover, +.text-link:hover { + color: #3DA1FF; +} + +/* Needed to override normal button style from inContent.css */ +button.button-link:not([disabled="true"]):active:hover { + background: transparent; + border: none; + box-shadow: none; +} + +.header-button { + -moz-appearance: none; + padding: 1px 3px; + color: #444; + text-shadow: 0 0 3px white; + background: linear-gradient(rgba(251, 252, 253, 0.95), transparent 49%, + rgba(211, 212, 213, 0.45) 51%, rgba(225, 226, 229, 0.3)); + background-clip: padding-box; + border: 1px solid rgba(31, 64, 100, 0.4); + border-top-color: rgba(31, 64, 100, 0.3); + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.25) inset, + 0 0 2px 1px rgba(255, 255, 255, 0.25) inset; +} + +%ifdef XP_WIN +@media (-moz-os-version: windows-vista), + (-moz-os-version: windows-win7) { +%endif + .header-button { + border-radius: 2.5px; + } +%ifdef XP_WIN +} +%endif + +.header-button[disabled="true"] { + opacity: 0.8; +} + +.header-button[disabled="true"] > .toolbarbutton-icon { + opacity: 0.4; +} + +.header-button:not([disabled="true"]):active:hover, +.header-button[open="true"] { + background-color: rgba(61, 76, 92, 0.2); + border-color: rgba(39, 53, 68, 0.5); + box-shadow: 0 0 3px 1px rgba(39, 53, 68, 0.2) inset; +} + +.header-button > .toolbarbutton-text { + display: none; +} + +/*** telemetry experiments ***/ + +#detail-experiment-container { + font-size: 80%; + margin-bottom: 1em; +} + +#detail-experiment-bullet-container, +#detail-experiment-state, +#detail-experiment-time, +.experiment-bullet-container, +.experiment-state, +.experiment-time { + vertical-align: middle; + display: inline-block; +} + +.addon .experiment-bullet, +#detail-experiment-bullet { + fill: rgb(158, 158, 158); +} + +.addon[active="true"] .experiment-bullet, +#detail-view[active="true"] #detail-experiment-bullet { + fill: rgb(106, 201, 20); +} diff --git a/toolkit/themes/windows/mozapps/extensions/heart.png b/toolkit/themes/windows/mozapps/extensions/heart.png new file mode 100644 index 000000000..655f4c4be Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/heart.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/localeGeneric.png b/toolkit/themes/windows/mozapps/extensions/localeGeneric.png new file mode 100644 index 000000000..623ba3a6a Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/localeGeneric.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/navigation.png b/toolkit/themes/windows/mozapps/extensions/navigation.png new file mode 100644 index 000000000..8ff639127 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/navigation.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/newaddon.css b/toolkit/themes/windows/mozapps/extensions/newaddon.css new file mode 100644 index 000000000..b3c429ec7 --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/newaddon.css @@ -0,0 +1,110 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +@import url("chrome://global/skin/inContentUI.css"); + +#addon-page { + padding: 0; +} + +#addon-scrollbox { + overflow: auto; + -moz-box-orient: vertical; + -moz-box-flex: 1; +} + +#spacer-start { + -moz-box-flex: 1; +} + +#spacer-end { + -moz-box-flex: 3; +} + +#addon-container { + overflow: visible; + max-width: 600px; + margin: 20px; + padding: 30px 90px; +} + +#addon-info { + -moz-box-align: start; + margin: 25px 10px; +} + +#icon { + -moz-margin-end: 10px; + max-width: 64px; + max-height: 64px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +} + +.addon-info[type="theme"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +.addon-info[type="locale"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +.addon-info[type="plugin"] #icon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +.addon-info[type="dictionary"] #icon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} + +#name { + font-size: 130%; +} + +#author { + color: GrayText; +} + +#location { + color: GrayText; +} + +#warning { + margin-bottom: 25px; + -moz-box-align: start; +} + +#warning-icon { + list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.png"); + width: 16px; + height: 15px; + -moz-margin-end: 5px; +} + +#allow { + -moz-margin-start: 84px; + margin-bottom: 20px; +} + +#continuePanel, +#restartPanel { + margin-top: 25px; + -moz-box-pack: end; + -moz-box-align: center; +} + +#continuePanel { + -moz-box-pack: end; +} + +#restartMessage { + text-align: right; +} + +#restartSpacer { + -moz-box-flex: 1; +} + +#later { + color: GrayText; +} diff --git a/toolkit/themes/windows/mozapps/extensions/rating-not-won.png b/toolkit/themes/windows/mozapps/extensions/rating-not-won.png new file mode 100644 index 000000000..2761f1925 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/rating-not-won.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/rating-won.png b/toolkit/themes/windows/mozapps/extensions/rating-won.png new file mode 100644 index 000000000..336dd8f6e Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/rating-won.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/selectAddons.css b/toolkit/themes/windows/mozapps/extensions/selectAddons.css new file mode 100644 index 000000000..e15ca9c72 --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/selectAddons.css @@ -0,0 +1,185 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#view-deck { + background: Window; +} + +.heading { + font-size: 270%; + text-align: center; + margin: 0 120px; +} + +.progress { + margin: 10px 128px; +} + +.progress-label, +#errors-description { + text-align: center; + margin: 0 10px; +} + +#checking-heading, +#update-heading, +#errors-heading { + margin-top: 90px; +} + +#select-heading, +#confirm-heading { + margin-top: 10px; + margin-bottom: 10px; + text-align: center; +} + +#select-description, +#confirm-description { + margin: 10px; +} + +#select-list { + border-top: 1px solid #D6E5F5; + background-color: Window; +} + +#select-grid column { + -moz-box-align: center; +} + +#select-grid row { + -moz-box-align: stretch; +} + +#select-grid label { + margin-top: 0; + margin-bottom: 0; +} + +.select-cell { + -moz-box-align: center; + -moz-box-pack: start; +} + +#select-header .select-cell { + box-sizing: border-box; +} + +#select-header .select-keep, +#select-header .select-icon, +#select-header .select-name, +#select-header .select-action { + background-image: linear-gradient(#D6E5F5 0%, Window 100%); + background-size: 1px 100%; + background-position: right; + background-repeat: no-repeat; +} + +.select-keep { + -moz-box-pack: center; +} + +.select-icon { + width: 20px; +} + +.select-keep .addon-keep-checkbox { + margin: 0; + padding: 0; + width: 13px; +} + +.select-keep .addon-keep-checkbox:-moz-focusring { + outline: 1px dotted ThreeDDarkShadow; +} + +.select-keep .checkbox-label-box { + display: none; +} + +.addon-name, +.addon-action-message, +.addon-action-update { + box-sizing: border-box; + margin: 0; + padding-top: 1px; + padding-bottom: 2px; + -moz-padding-start: 6px; + -moz-padding-end: 5px; +} + +#select-grid separator { + border-top: 1px solid #D6E5F5; + height: 0; + margin-top: 0.4em; + margin-bottom: 0.4em; +} + +.addon:not([active]) .addon-name, +.addon:not([active]) .addon-action-message, +.addon:not([active]) .addon-action-update { + color: GrayText; +} + +.addon-icon { + height: 16px; + width: 16px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png"); +} + +.addon-icon[type="theme"] { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric-16.png"); +} + +.addon-icon[type="plugin"] { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric-16.png"); +} + +.addon-icon[type="dictionary"] { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric-16.png"); +} + +.action-list { + margin-top: 10px; + -moz-margin-start: 5em; +} + +.action-header { + margin-bottom: 10px; +} + +#confirm .addon { + -moz-margin-start: 3em; + -moz-box-align: center; +} + +.addon:not([active]) .addon-icon, +#disable-list .addon-icon, +#incompatible-list .addon-icon { + filter: grayscale(1); +} + +#footer { + padding: 15px 12px; +} + +.progress-label, +#footer-label { + color: GrayText; +} + +%ifdef XP_WIN +.progress-label, +#footer-label { + font-style: italic; +} + +@media (-moz-windows-default-theme) { + #footer { + background-color: #f1f5fb; + box-shadow: 0px 1px 2px rgb(204,214,234) inset; + } +} +%endif diff --git a/toolkit/themes/windows/mozapps/extensions/stripes-error.png b/toolkit/themes/windows/mozapps/extensions/stripes-error.png new file mode 100644 index 000000000..1dc2d8504 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/stripes-error.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/stripes-info-negative.png b/toolkit/themes/windows/mozapps/extensions/stripes-info-negative.png new file mode 100644 index 000000000..901ab1ec2 Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/stripes-info-negative.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/stripes-info-positive.png b/toolkit/themes/windows/mozapps/extensions/stripes-info-positive.png new file mode 100644 index 000000000..370ceec0f Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/stripes-info-positive.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/stripes-warning.png b/toolkit/themes/windows/mozapps/extensions/stripes-warning.png new file mode 100644 index 000000000..69463fb1a Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/stripes-warning.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/themeGeneric-16.png b/toolkit/themes/windows/mozapps/extensions/themeGeneric-16.png new file mode 100644 index 000000000..ff13ce37f Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/themeGeneric-16.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/themeGeneric.png b/toolkit/themes/windows/mozapps/extensions/themeGeneric.png new file mode 100644 index 000000000..9cea549dd Binary files /dev/null and b/toolkit/themes/windows/mozapps/extensions/themeGeneric.png differ diff --git a/toolkit/themes/windows/mozapps/extensions/update.css b/toolkit/themes/windows/mozapps/extensions/update.css new file mode 100644 index 000000000..d35438ac9 --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/update.css @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#alert { + list-style-image: url("chrome://mozapps/skin/update/update.png"); +} + +.throbber { + list-style-image: url("chrome://global/skin/icons/loading_16.png"); + width: 16px; + height: 16px; + margin-top: 5px; + margin-bottom: 5px; + -moz-margin-start: 5px; + -moz-margin-end: 2px; +} + +.alertBox { + background-color: InfoBackground; + color: InfoText; + border: 1px outset InfoBackground; + margin-left: 3px; + margin-right: 3px; + padding: 5px; +} diff --git a/toolkit/themes/windows/mozapps/extensions/xpinstallConfirm.css b/toolkit/themes/windows/mozapps/extensions/xpinstallConfirm.css new file mode 100644 index 000000000..d038e1abf --- /dev/null +++ b/toolkit/themes/windows/mozapps/extensions/xpinstallConfirm.css @@ -0,0 +1,101 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#xpinstallheader { + margin-bottom: 2em; +} + +#itemList { + -moz-appearance: listbox; + margin: 3px 4px 10px 4px; + height: 14em; + border: 2px solid; + -moz-border-top-colors: ThreeDShadow ThreeDDarkShadow; + -moz-border-right-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-bottom-colors: ThreeDHighlight ThreeDLightShadow; + -moz-border-left-colors: ThreeDShadow ThreeDDarkShadow; + background-color: -moz-Field; + color: -moz-FieldText; +} + +#itemWarningIntro { + -moz-margin-start: 8px; +} + +#dialogContentBox { + padding: 5px; +} + +installitem { + padding-top: 5px; + padding-bottom: 5px; + -moz-padding-start: 5px; + -moz-padding-end: 0; + border-bottom: 1px dotted #C0C0C0; + margin-bottom: 5px; +} + +.alert-icon { +%ifdef XP_WIN + list-style-image: url("chrome://global/skin/icons/warning-large.png"); + width: 48px; + height: 48px; +%endif + -moz-margin-end: 20px; +} + +.warning { + font-weight: bold; + font-size: 1.25em; + margin-bottom: 1em; +} + +.xpinstallIconContainer { + width: 32px; + height: 32px; + -moz-margin-end: 5px; +} + +.xpinstallItemName { + font-weight: bold; +} + +.xpinstallItemSigned { + font-style: italic; + font-size: 0.9em; +} + +.xpinstallItemURL { + -moz-appearance: none; + border: none; + padding: 0; + background-color: -moz-Field; + color: -moz-FieldText; + margin-top: 1px; + margin-bottom: 1px; + -moz-margin-start: 6px; + -moz-margin-end: 5px; +} + +.xpinstallItemIcon { + max-width: 32px; + max-height: 32px; + list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png"); +} + +installitem[type="theme"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/themeGeneric.png"); +} + +installitem[type="locale"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/localeGeneric.png"); +} + +installitem[type="plugin"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png"); +} + +installitem[type="dictionary"] .xpinstallItemIcon { + list-style-image: url("chrome://mozapps/skin/extensions/dictionaryGeneric.png"); +} -- cgit v1.2.3