tor-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
July 2016
- 21 participants
- 1271 discussions

[tor-messenger-build/master] Fix typo in Firefox-update-process-bug-4234.mozpatch
by arlo@torproject.org 28 Jul '16
by arlo@torproject.org 28 Jul '16
28 Jul '16
commit b61a35f82e5b19420a532c7970dc28c11870fd1f
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Mon Jul 18 17:34:44 2016 -0400
Fix typo in Firefox-update-process-bug-4234.mozpatch
---
projects/instantbird/Firefox-update-process-bug-4234.mozpatch | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/projects/instantbird/Firefox-update-process-bug-4234.mozpatch b/projects/instantbird/Firefox-update-process-bug-4234.mozpatch
index a02d80b..8df0b37 100644
--- a/projects/instantbird/Firefox-update-process-bug-4234.mozpatch
+++ b/projects/instantbird/Firefox-update-process-bug-4234.mozpatch
@@ -265,7 +265,7 @@ index 38df30e..e9fb038 100644
dnl ========================================================
+dnl Tor Additions
+dnl ========================================================
-+MOZ_ARG_WITH_STRING(eor-browser-version,
++MOZ_ARG_WITH_STRING(tor-browser-version,
+[ --with-tor-browser-version=VERSION
+ Set Tor Browser version, e.g., 4.0b1],
+ TOR_BROWSER_VERSION="$withval")
1
0

28 Jul '16
commit 9cfd3634a5ab22c39b0ec715e3410c4ebebc5ed1
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Mon Jul 18 12:41:06 2016 -0400
Add patch or #16940 (also #14392)
---
...ate-load-local-changes-bug-14392-first.mozpatch | 18 +
...te-load-local-changes-bug-16940-second.mozpatch | 368 +++++++++++++++++++++
projects/instantbird/aboutTBUpdateLogo.png | Bin 0 -> 2724 bytes
3 files changed, 386 insertions(+)
diff --git a/projects/instantbird/Update-load-local-changes-bug-14392-first.mozpatch b/projects/instantbird/Update-load-local-changes-bug-14392-first.mozpatch
new file mode 100644
index 0000000..e1bc5bf
--- /dev/null
+++ b/projects/instantbird/Update-load-local-changes-bug-14392-first.mozpatch
@@ -0,0 +1,18 @@
+commit bb781597694015aed8ea4d121eac503542fd52f2
+Author: Mike Perry <mikeperry-git(a)torproject.org>
+Date: Wed Feb 11 16:45:24 2015 -0800
+
+ Bug 14392: Make about:tor behave like other initial pages.
+
+diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
+index 4f2642a..934a223 100644
+--- a/browser/base/content/browser.js
++++ b/browser/base/content/browser.js
+@@ -258,6 +258,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
+ "resource://gre/modules/LoginManagerParent.jsm");
+
+ var gInitialPages = [
++ "about:tor",
+ "about:blank",
+ "about:newtab",
+ "about:home",
diff --git a/projects/instantbird/Update-load-local-changes-bug-16940-second.mozpatch b/projects/instantbird/Update-load-local-changes-bug-16940-second.mozpatch
new file mode 100644
index 0000000..25aac2a
--- /dev/null
+++ b/projects/instantbird/Update-load-local-changes-bug-16940-second.mozpatch
@@ -0,0 +1,368 @@
+From 3815bb323160cf9163a07e36859c2ea83c905ace Mon Sep 17 00:00:00 2001
+From: Kathy Brade <brade(a)pearlcrescent.com>
+Date: Wed, 25 Nov 2015 11:36:20 -0500
+Subject: Bug 16940: After update, load local change notes.
+
+Add an about:tbupdate page that displays the first section from
+TorBrowser/Docs/ChangeLog.txt and includes a link to the remote
+post-update page (typically our blog entry for the release).
+
+diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.css b/browser/base/content/abouttbupdate/aboutTBUpdate.css
+new file mode 100644
+index 0000000..489c9d2
+--- /dev/null
++++ b/browser/base/content/abouttbupdate/aboutTBUpdate.css
+@@ -0,0 +1,34 @@
++body {
++ font-family: sans-serif;
++ font-size: 110%;
++ background-image: -moz-linear-gradient(top, #ffffff, #ffffff 10%, #d5ffd5 50%, #d5ffd5);
++ background-attachment: fixed;
++ background-size: 100% 100%;
++}
++
++#logo {
++ background-image: url("chrome://browser/content/abouttbupdate/aboutTBUpdateLogo.png");
++ height: 128px;
++ width: 128px;
++ margin: 20px;
++ float: left;
++}
++
++#msg {
++ margin-top: 50px;
++ float: left;
++}
++
++#msg-updated {
++ font-size: 120%;
++ margin-bottom: 20px;
++}
++
++#changelog-container {
++ margin: 0px 20px 20px 20px;
++}
++
++#changelog {
++ margin-left: 20px;
++ white-space: pre;
++}
+diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.js b/browser/base/content/abouttbupdate/aboutTBUpdate.js
+new file mode 100644
+index 0000000..8243647
+--- /dev/null
++++ b/browser/base/content/abouttbupdate/aboutTBUpdate.js
+@@ -0,0 +1,10 @@
++// Copyright (c) 2015, The Tor Project, Inc.
++// See LICENSE for licensing information.
++//
++// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
++
++function init()
++{
++ let event = new CustomEvent("AboutTBUpdateLoad", { bubbles: true });
++ document.dispatchEvent(event);
++}
+diff --git a/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml b/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
+new file mode 100644
+index 0000000..3a29e0c
+--- /dev/null
++++ b/browser/base/content/abouttbupdate/aboutTBUpdate.xhtml
+@@ -0,0 +1,34 @@
++<?xml version="1.0" encoding="UTF-8"?>
++
++<!DOCTYPE html [
++ <!ENTITY % htmlDTD
++ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
++ "DTD/xhtml1-strict.dtd">
++ %htmlDTD;
++ <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
++ %globalDTD;
++ <!ENTITY % tbUpdateDTD SYSTEM "chrome://browser/locale/aboutTBUpdate.dtd">
++ %tbUpdateDTD;
++]>
++
++<html xmlns="http://www.w3.org/1999/xhtml">
++<head>
++ <title>&aboutTBUpdate.title;</title>
++ <link rel="stylesheet" type="text/css"
++ href="chrome://browser/content/abouttbupdate/aboutTBUpdate.css"/>
++ <script src="chrome://browser/content/abouttbupdate/aboutTBUpdate.js"
++ type="text/javascript;version=1.7"/>
++</head>
++<body dir="&locale.dir;" onload="init()">
++<div id="logo"/>
++<div id="msg">
++<div id="msg-updated">&aboutTBUpdate.updated;</div>
++<div>&aboutTBUpdate.linkPrefix;<a id="infolink">&aboutTBUpdate.linkLabel;</a>&aboutTBUpdate.linkSuffix;
++</div>
++</div>
++<br clear="all"/>
++<div id="changelog-container">&aboutTBUpdate.changeLogHeading;
++<div id="changelog"></div>
++</div>
++</body>
++</html>
+diff --git a/browser/base/content/abouttbupdate/aboutTBUpdateLogo.png b/browser/base/content/abouttbupdate/aboutTBUpdateLogo.png
+new file mode 100644
+index 0000000..be5cae9
+Binary files /dev/null and b/browser/base/content/abouttbupdate/aboutTBUpdateLogo.png differ
+diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
+index 6e78084..0adbe61 100644
+--- a/browser/base/content/browser.js
++++ b/browser/base/content/browser.js
+@@ -259,6 +259,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
+
+ var gInitialPages = [
+ "about:tor",
++#ifdef TOR_BROWSER_UPDATE
++ "about:tbupdate",
++#endif
+ "about:blank",
+ "about:newtab",
+ "about:home",
+@@ -2425,8 +2428,14 @@ function URLBarSetURI(aURI) {
+
+ // Replace initial page URIs with an empty string
+ // only if there's no opener (bug 370555).
++#ifdef TOR_BROWSER_UPDATE
++ if (gInitialPages.indexOf(uri.spec.split('?')[0]) != -1 &&
++ checkEmptyPageOrigin(gBrowser.selectedBrowser, uri))
++#else
+ if (gInitialPages.indexOf(uri.spec) != -1 &&
+- checkEmptyPageOrigin(gBrowser.selectedBrowser, uri)) {
++ checkEmptyPageOrigin(gBrowser.selectedBrowser, uri))
++#endif
++ {
+ value = "";
+ } else {
+ value = losslessDecodeURI(uri);
+@@ -7043,7 +7052,11 @@ var gIdentityHandler = {
+ this._uriHasHost = false;
+ }
+
+- let whitelist = /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback)(?:[?#]|$)/i;
++#ifdef TOR_BROWSER_UPDATE
++ let whitelist = /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback|tor|tbupdate)(?:[?#]|$)/i;
++#else
++ let whitelist = /^(?:accounts|addons|cache|config|crashes|customizing|downloads|healthreport|home|license|newaddon|permissions|preferences|privatebrowsing|rights|sessionrestore|support|welcomeback|tor)(?:[?#]|$)/i;
++#endif
+ this._isSecureInternalUI = uri.schemeIs("about") && whitelist.test(uri.path);
+
+ this._sslStatus = gBrowser.securityUI
+diff --git a/browser/base/content/tab-content.js b/browser/base/content/tab-content.js
+index c8f39ee..44489a2 100644
+--- a/browser/base/content/tab-content.js
++++ b/browser/base/content/tab-content.js
+@@ -10,6 +10,9 @@ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+ Cu.import("resource://gre/modules/Services.jsm");
+ Cu.import("resource://gre/modules/ExtensionContent.jsm");
++#ifdef TOR_BROWSER_UPDATE
++Cu.import("resource://gre/modules/NetUtil.jsm");
++#endif
+
+ XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+ "resource:///modules/E10SUtils.jsm");
+@@ -368,6 +371,82 @@ var AboutReaderListener = {
+ };
+ AboutReaderListener.init();
+
++#ifdef TOR_BROWSER_UPDATE
++let AboutTBUpdateListener = {
++ init: function(chromeGlobal) {
++ chromeGlobal.addEventListener('AboutTBUpdateLoad', this, false, true);
++ },
++
++ get isAboutTBUpdate() {
++ return content.document.documentURI.split('?')[0].toLowerCase()
++ == "about:tbupdate";
++ },
++
++ handleEvent: function(aEvent) {
++ if (this.isAboutTBUpdate && (aEvent.type == "AboutTBUpdateLoad"))
++ this.onPageLoad();
++ },
++
++ onPageLoad: function() {
++ let doc = content.document;
++ doc.getElementById("infolink").setAttribute("href", this.getPostUpdateURL());
++ doc.getElementById("changelog").textContent = this.getChangeLogText();
++ },
++
++ // Extract the post update URL from this page's query string.
++ getPostUpdateURL: function() {
++ let idx = content.document.documentURI.indexOf('?');
++ if (idx > 0)
++ return decodeURIComponent(content.document.documentURI.substring(idx+1));
++
++ // No query string: use the default URL.
++ return Services.urlFormatter.formatURLPref("startup.homepage_override_url");
++ },
++
++ // Read and return the text from the beginning of the changelog file that is
++ // located at TorBrowser/Docs/ChangeLog.txt.
++ // On Mac OS, when building with --enable-tor-browser-data-outside-app-dir
++ // to support Gatekeeper signing, the file is located in
++ // TorBrowser.app/Contents/Resources/TorBrowser/Docs/.
++ //
++ // When electrolysis is enabled we will need to adopt an architecture that is
++ // more similar to the one that is used for about:home (see AboutHomeListener
++ // in this file and browser/modules/AboutHome.jsm).
++ getChangeLogText: function() {
++ try {
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ // "XREExeF".parent is the directory that contains firefox, i.e.,
++ // Browser/ or, on Mac OS, TorBrowser.app/Contents/MacOS/.
++ let f = Services.dirsvc.get("XREExeF", Ci.nsIFile).parent;
++#ifdef XP_MACOSX
++ f = f.parent;
++ f.append("Resources");
++#endif
++ f.append("TorBrowser");
++#else
++ // "DefProfRt" is .../TorBrowser/Data/Browser
++ let f = Cc["@mozilla.org/file/directory_service;1"]
++ .getService(Ci.nsIProperties).get("DefProfRt", Ci.nsIFile);
++ f = f.parent.parent; // Remove "Data/Browser"
++#endif
++ f.append("Docs");
++ f.append("ChangeLog.txt");
++
++ let fs = Cc["@mozilla.org/network/file-input-stream;1"]
++ .createInstance(Ci.nsIFileInputStream);
++ fs.init(f, -1, 0, 0);
++ let s = NetUtil.readInputStreamToString(fs, fs.available());
++ fs.close();
++
++ // Truncate at the first empty line.
++ return s.replace(/[\r\n][\r\n][\s\S]*$/m, "");
++ } catch (e) {}
++
++ return "";
++ },
++};
++AboutTBUpdateListener.init(this);
++#endif
+
+ var ContentSearchMediator = {
+
+diff --git a/browser/base/jar.mn b/browser/base/jar.mn
+index a39f8fa..45f6e09 100644
+--- a/browser/base/jar.mn
++++ b/browser/base/jar.mn
+@@ -73,8 +73,14 @@ browser.jar:
+ content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
+ * content/browser/aboutTabGroupsMigration.xhtml (content/aboutTabGroupsMigration.xhtml)
+ content/browser/aboutTabGroupsMigration.js (content/aboutTabGroupsMigration.js)
++#ifdef TOR_BROWSER_UPDATE
++ content/browser/abouttbupdate/aboutTBUpdate.xhtml (content/abouttbupdate/aboutTBUpdate.xhtml)
++ content/browser/abouttbupdate/aboutTBUpdate.js (content/abouttbupdate/aboutTBUpdate.js)
++ content/browser/abouttbupdate/aboutTBUpdate.css (content/abouttbupdate/aboutTBUpdate.css)
++ content/browser/abouttbupdate/aboutTBUpdateLogo.png (content/abouttbupdate/aboutTBUpdateLogo.png)
++#endif
+ * content/browser/browser.css (content/browser.css)
+- content/browser/browser.js (content/browser.js)
++* content/browser/browser.js (content/browser.js)
+ * content/browser/browser.xul (content/browser.xul)
+ content/browser/browser-addons.js (content/browser-addons.js)
+ content/browser/browser-ctrlTab.js (content/browser-ctrlTab.js)
+@@ -104,7 +110,7 @@ browser.jar:
+ content/browser/browser-thumbnails.js (content/browser-thumbnails.js)
+ content/browser/browser-trackingprotection.js (content/browser-trackingprotection.js)
+ * content/browser/chatWindow.xul (content/chatWindow.xul)
+- content/browser/tab-content.js (content/tab-content.js)
++* content/browser/tab-content.js (content/tab-content.js)
+ content/browser/content.js (content/content.js)
+ content/browser/social-content.js (content/social-content.js)
+ content/browser/defaultthemes/1.footer.jpg (content/defaultthemes/1.footer.jpg)
+diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
+index 78f55c9..ab069e5 100644
+--- a/browser/components/about/AboutRedirector.cpp
++++ b/browser/components/about/AboutRedirector.cpp
+@@ -138,6 +138,13 @@ static RedirEntry kRedirMap[] = {
+ nsIAboutModule::ALLOW_SCRIPT |
+ nsIAboutModule::HIDE_FROM_ABOUTABOUT |
+ nsIAboutModule::MAKE_UNLINKABLE },
++#ifdef TOR_BROWSER_UPDATE
++ { "tbupdate", "chrome://browser/content/abouttbupdate/aboutTBUpdate.xhtml",
++ nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
++ nsIAboutModule::ALLOW_SCRIPT |
++ nsIAboutModule::MAKE_UNLINKABLE |
++ nsIAboutModule::HIDE_FROM_ABOUTABOUT },
++#endif
+ };
+ static const int kRedirTotal = ArrayLength(kRedirMap);
+
+diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp
+index 7950d7c..a316cb3 100644
+--- a/browser/components/build/nsModule.cpp
++++ b/browser/components/build/nsModule.cpp
+@@ -115,6 +115,9 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
+ { NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+ { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-saved", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+ { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-signup", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
++#ifdef TOR_BROWSER_UPDATE
++ { NS_ABOUT_MODULE_CONTRACTID_PREFIX "tbupdate", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
++#endif
+ #if defined(XP_WIN)
+ { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
+ #elif defined(XP_MACOSX)
+diff --git a/browser/components/nsBrowserContentHandler.js b/browser/components/nsBrowserContentHandler.js
+index b892eaf..8cc5cc5 100644
+--- a/browser/components/nsBrowserContentHandler.js
++++ b/browser/components/nsBrowserContentHandler.js
+@@ -573,6 +573,13 @@ nsBrowserContentHandler.prototype = {
+ // into account because that requires waiting for the session file
+ // to be read. If a crash occurs after updating, before restarting,
+ // we may open the startPage in addition to restoring the session.
++ //
++ // Tor Browser: Instead of opening the post-update "override page"
++ // directly, an about:tbupdate page is opened that includes a link
++ // to the override page as well as text from the first part of the
++ // local ChangeLog.txt file. The override page URL comes from the
++ // openURL attribute within the updates.xml file or, if no showURL
++ // action is present, from the startup.homepage_override_url pref.
+ var ss = Components.classes["@mozilla.org/browser/sessionstartup;1"]
+ .getService(Components.interfaces.nsISessionStartup);
+ willRestoreSession = ss.isAutomaticRestoreEnabled();
+@@ -586,6 +593,11 @@ nsBrowserContentHandler.prototype = {
+ overridePage = overridePage.replace("%OLD_TOR_BROWSER_VERSION%",
+ old_tbversion);
+ #endif
++
++#ifdef TOR_BROWSER_UPDATE
++ if (overridePage)
++ overridePage = "about:tbupdate?" + encodeURIComponent(overridePage);
++#endif
+ break;
+ }
+ }
+diff --git a/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd b/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd
+new file mode 100644
+index 0000000..37567bd
+--- /dev/null
++++ b/browser/locales/en-US/chrome/browser/aboutTBUpdate.dtd
+@@ -0,0 +1,6 @@
++<!ENTITY aboutTBUpdate.title "Tor Messenger Update">
++<!ENTITY aboutTBUpdate.updated "Tor Messenger has been updated.">
++<!ENTITY aboutTBUpdate.linkPrefix "For the most up-to-date information about this release, ">
++<!ENTITY aboutTBUpdate.linkLabel "visit our website">
++<!ENTITY aboutTBUpdate.linkSuffix ".">
++<!ENTITY aboutTBUpdate.changeLogHeading "Changelog:">
+diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn
+index 44c5e6a..0f18e06 100644
+--- a/browser/locales/jar.mn
++++ b/browser/locales/jar.mn
+@@ -21,6 +21,9 @@
+ locale/browser/aboutTabCrashed.dtd (%chrome/browser/aboutTabCrashed.dtd)
+ locale/browser/syncCustomize.dtd (%chrome/browser/syncCustomize.dtd)
+ locale/browser/aboutSyncTabs.dtd (%chrome/browser/aboutSyncTabs.dtd)
++#ifdef TOR_BROWSER_UPDATE
++ locale/browser/aboutTBUpdate.dtd (%chrome/browser/aboutTBUpdate.dtd)
++#endif
+ locale/browser/browser.dtd (%chrome/browser/browser.dtd)
+ locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd)
+ locale/browser/browser.properties (%chrome/browser/browser.properties)
+--
+cgit v0.10.2
diff --git a/projects/instantbird/aboutTBUpdateLogo.png b/projects/instantbird/aboutTBUpdateLogo.png
new file mode 100644
index 0000000..3de3c93
Binary files /dev/null and b/projects/instantbird/aboutTBUpdateLogo.png differ
1
0

[tor-messenger-build/master] ADd patch for #13252 (outside app directory)
by arlo@torproject.org 28 Jul '16
by arlo@torproject.org 28 Jul '16
28 Jul '16
commit d629613da79e6aaf77a4e1c625f6f83f916e7e80
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Mon Jul 18 12:40:35 2016 -0400
ADd patch for #13252 (outside app directory)
---
.../Mac-outside-app-data-bug-13252.mozpatch | 1124 ++++++++++++++++++++
1 file changed, 1124 insertions(+)
diff --git a/projects/instantbird/Mac-outside-app-data-bug-13252.mozpatch b/projects/instantbird/Mac-outside-app-data-bug-13252.mozpatch
new file mode 100644
index 0000000..a68f446
--- /dev/null
+++ b/projects/instantbird/Mac-outside-app-data-bug-13252.mozpatch
@@ -0,0 +1,1124 @@
+From 4f8084edd80a3726e9a995ff3407331807401558 Mon Sep 17 00:00:00 2001
+From: Kathy Brade <brade(a)pearlcrescent.com>
+Date: Fri, 18 Mar 2016 14:20:02 -0400
+Subject: Bug 13252 - Do not store data in the app bundle
+
+Add an --enable-tor-browser-data-outside-app-dir configure option.
+When this is enabled, all user data is stored in a directory named
+TorBrowser-Data which is located next to the application directory.
+
+The first time an updated browser is opened, migrate the existing
+browser profile, Tor data directory contents, and UpdateInfo to the
+TorBrowser-Data directory. If migration of the browser profile
+fails, an error alert is displayed and the browser is started
+using a new profile.
+
+Display an informative error messages if the TorBrowser-Data
+directory cannot be created due to an "access denied" or a
+"read only volume" error.
+
+Add support for installing "override" preferences within the user's
+browser profile. All .js files in distribution/preferences (on
+Mac OS, Contents/Resources/distribution/preferences) will be copied
+to the preferences directory within the user's browser profile when
+the profile is created and each time Tor Browser is updated. This
+mechanism will be used to install the extension-overrides.js file
+into the profile.
+
+On Mac OS, add support for the --invisible command line option which
+is used by the meek-http-helper to avoid showing an icon for the
+helper browser on the dock.
+
+diff --git a/configure.in b/configure.in
+index e9fb038..885ee84 100644
+--- a/configure.in
++++ b/configure.in
+@@ -6538,9 +6538,20 @@ if test -n "$TOR_BROWSER_UPDATE"; then
+ AC_DEFINE(TOR_BROWSER_UPDATE)
+ fi
+
++MOZ_ARG_ENABLE_BOOL(tor-browser-data-outside-app-dir,
++[ --enable-tor-browser-data-outside-app-dir
++ Enable Tor Browser data outside of app directory],
++ TOR_BROWSER_DATA_OUTSIDE_APP_DIR=1,
++ TOR_BROWSER_DATA_OUTSIDE_APP_DIR= )
++
++if test -n "$TOR_BROWSER_DATA_OUTSIDE_APP_DIR"; then
++ AC_DEFINE(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++fi
++
+ AC_DEFINE_UNQUOTED(TOR_BROWSER_VERSION,"$TOR_BROWSER_VERSION")
+ AC_SUBST(TOR_BROWSER_VERSION)
+ AC_SUBST(TOR_BROWSER_UPDATE)
++AC_SUBST(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
+
+ dnl ========================================================
+ dnl build the tests by default
+diff --git a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
+index 3cf48ff..f5cb77a 100644
+--- a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
++++ b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
+@@ -17,6 +17,7 @@ profileProblemTitle=%S Profile Problem
+ profileReadOnly=You cannot run %S from a read-only file system. Please copy %S to another location before trying to use it.
+ profileReadOnlyMac=You cannot run %S from a read-only file system. Please copy %S to your Desktop or Applications folder before trying to use it.
+ profileAccessDenied=%S does not have permission to access the profile. Please adjust your file system permissions and try again.
++profileMigrationFailed=Migration of your existing %S profile failed.\nNew settings will be used.
+ # Profile manager
+ # LOCALIZATION NOTE (profileTooltip): First %S is the profile name, second %S is the path to the profile folder.
+ profileTooltip=Profile: '%S' - Path: '%S'
+diff --git a/toolkit/mozapps/extensions/AddonManager.jsm b/toolkit/mozapps/extensions/AddonManager.jsm
+index a453062..e2d4e44 100644
+--- a/toolkit/mozapps/extensions/AddonManager.jsm
++++ b/toolkit/mozapps/extensions/AddonManager.jsm
+@@ -45,6 +45,11 @@ const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
+ const PREF_SELECTED_LOCALE = "general.useragent.locale";
+ const UNKNOWN_XPCOM_ABI = "unknownABI";
+
++#ifdef TOR_BROWSER_VERSION
++#expand const TOR_BROWSER_VERSION = __TOR_BROWSER_VERSION__;
++const PREF_EM_LAST_TORBROWSER_VERSION = "extensions.lastTorBrowserVersion";
++#endif
++
+ const PREF_MIN_WEBEXT_PLATFORM_VERSION = "extensions.webExtensionsMinPlatformVersion";
+
+ const UPDATE_REQUEST_VERSION = 2;
+@@ -910,6 +915,30 @@ var AddonManagerInternal = {
+ this.validateBlocklist();
+ }
+
++#ifdef TOR_BROWSER_VERSION
++ // To ensure that extension override prefs are reinstalled into the
++ // user's profile after each update, set appChanged = true if the
++ // Mozilla app version has not changed but the Tor Browser version
++ // has changed.
++ let tbChanged = undefined;
++ try {
++ tbChanged = TOR_BROWSER_VERSION !=
++ Services.prefs.getCharPref(PREF_EM_LAST_TORBROWSER_VERSION);
++ }
++ catch (e) { }
++ if (tbChanged !== false) {
++ // Because PREF_EM_LAST_TORBROWSER_VERSION was not present in older
++ // versions of Tor Browser, an app change is indicated when tbChanged
++ // is undefined or true.
++ if (appChanged === false) {
++ appChanged = true;
++ }
++
++ Services.prefs.setCharPref(PREF_EM_LAST_TORBROWSER_VERSION,
++ TOR_BROWSER_VERSION);
++ }
++#endif
++
+ if (!MOZ_COMPATIBILITY_NIGHTLY) {
+ PREF_EM_CHECK_COMPATIBILITY = PREF_EM_CHECK_COMPATIBILITY_BASE + "." +
+ Services.appinfo.version.replace(BRANCH_REGEXP, "$1");
+diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+index 7a58a7d..51c51b8 100644
+--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
++++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+@@ -130,6 +130,7 @@ const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/exte
+ const STRING_TYPE_NAME = "type.%ID%.name";
+
+ const DIR_EXTENSIONS = "extensions";
++const DIR_PREFERENCES = "preferences";
+ const DIR_SYSTEM_ADDONS = "features";
+ const DIR_STAGE = "staged";
+ const DIR_TRASH = "trash";
+@@ -3510,6 +3511,58 @@ this.XPIProvider = {
+ return changed;
+ },
+
++ /**
++ * Installs any preference files located in the preferences directory of the
++ * application's distribution specific directory into the profile.
++ *
++ * @return true if any preference files were installed
++ */
++ installDistributionPreferences: function XPI_installDistributionPreferences() {
++ let distroDir;
++ try {
++ distroDir = FileUtils.getDir(KEY_APP_DISTRIBUTION, [DIR_PREFERENCES]);
++ }
++ catch (e) {
++ return false;
++ }
++
++ if (!distroDir.exists() || !distroDir.isDirectory())
++ return false;
++
++ let changed = false;
++ let prefOverrideDir = Services.dirsvc.get("PrefDOverride", Ci.nsIFile);
++
++ let entries = distroDir.directoryEntries
++ .QueryInterface(Ci.nsIDirectoryEnumerator);
++ let entry;
++ while ((entry = entries.nextFile)) {
++ let fileName = entry.leafName;
++ if (!entry.isFile() ||
++ fileName.substring(fileName.length - 3).toLowerCase() != ".js") {
++ logger.debug("Ignoring distribution preference that isn't a JS file: "
++ + entry.path);
++ continue;
++ }
++
++ try {
++ if (!prefOverrideDir.exists()) {
++ prefOverrideDir.create(Ci.nsIFile.DIRECTORY_TYPE,
++ FileUtils.PERMS_DIRECTORY);
++ }
++
++ entry.copyTo(prefOverrideDir, null);
++ changed = true;
++ } catch (e) {
++ logger.debug("Unable to copy " + entry.path + " to " +
++ prefOverrideDir.path);
++ }
++ }
++
++ entries.close();
++
++ return changed;
++ },
++
+ /**
+ * Imports the xpinstall permissions from preferences into the permissions
+ * manager for the user to change later.
+@@ -3583,6 +3636,12 @@ this.XPIProvider = {
+ if (updated) {
+ updateReasons.push("installDistributionAddons");
+ }
++
++ // Also copy distribution preferences to the user's profile.
++ updated = this.installDistributionPreferences();
++ if (updated) {
++ updateReasons.push("installDistributionPreferences");
++ }
+ }
+
+ // Telemetry probe added around getInstallState() to check perf
+diff --git a/toolkit/mozapps/extensions/moz.build b/toolkit/mozapps/extensions/moz.build
+index 8fbd96d..06091a5 100644
+--- a/toolkit/mozapps/extensions/moz.build
++++ b/toolkit/mozapps/extensions/moz.build
+@@ -30,12 +30,15 @@ EXTRA_PP_COMPONENTS += [
+ ]
+
+ EXTRA_JS_MODULES += [
+- 'AddonManager.jsm',
+ 'ChromeManifestParser.jsm',
+ 'DeferredSave.jsm',
+ 'LightweightThemeManager.jsm',
+ ]
+
++EXTRA_PP_JS_MODULES += [
++ 'AddonManager.jsm',
++]
++
+ JAR_MANIFESTS += ['jar.mn']
+
+ EXPORTS.mozilla += [
+diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
+index a3a2857..20be296 100644
+--- a/toolkit/xre/nsAppRunner.cpp
++++ b/toolkit/xre/nsAppRunner.cpp
+@@ -1949,11 +1949,30 @@ GetOverrideStringBundle(nsIStringBundleService* aSBS, nsIStringBundle* *aResult)
+
+ *aResult = nullptr;
+
+- // Build Torbutton file URI string by starting from the profiles directory.
+ nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton();
+ if (!dirProvider)
+ return;
+
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ // Build Torbutton file URI by starting from the distribution directory.
++ bool persistent = false; // ignored
++ nsCOMPtr<nsIFile> distribDir;
++ nsresult rv = dirProvider->GetFile(XRE_APP_DISTRIBUTION_DIR, &persistent,
++ getter_AddRefs(distribDir));
++ if (NS_FAILED(rv))
++ return;
++
++ // Create file URI, extract as string, and append Torbutton xpi relative path.
++ nsCOMPtr<nsIURI> uri;
++ nsAutoCString uriString;
++ if (NS_FAILED(NS_NewFileURI(getter_AddRefs(uri), distribDir)) ||
++ NS_FAILED(uri->GetSpec(uriString))) {
++ return;
++ }
++
++ uriString.Append("extensions/torbutton(a)torproject.org.xpi");
++#else
++ // Build Torbutton file URI string by starting from the profiles directory.
+ bool persistent = false; // ignored
+ nsCOMPtr<nsIFile> profilesDir;
+ nsresult rv = dirProvider->GetFile(NS_APP_USER_PROFILES_ROOT_DIR, &persistent,
+@@ -1970,6 +1989,7 @@ GetOverrideStringBundle(nsIStringBundleService* aSBS, nsIStringBundle* *aResult)
+ }
+
+ uriString.Append("profile.default/extensions/torbutton(a)torproject.org.xpi");
++#endif
+
+ nsCString userAgentLocale;
+ if (!NS_SUCCEEDED(Preferences::GetCString("general.useragent.locale",
+@@ -2019,6 +2039,9 @@ enum ProfileStatus {
+ PROFILE_STATUS_READ_ONLY,
+ PROFILE_STATUS_IS_LOCKED,
+ PROFILE_STATUS_OTHER_ERROR
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ , PROFILE_STATUS_MIGRATION_FAILED
++#endif
+ };
+
+ static const char kProfileProperties[] =
+@@ -2058,6 +2081,8 @@ private:
+
+ } // namespace
+
++// If aUnlocker is NULL, it is also OK for the following arguments to be NULL:
++// aProfileDir, aProfileLocalDir, aResult.
+ static ReturnAbortOnError
+ ProfileErrorDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
+ ProfileStatus aStatus, nsIProfileUnlocker* aUnlocker,
+@@ -2069,7 +2094,8 @@ ProfileErrorDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
+ rv = xpcom.Initialize();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+- mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
++ if (aProfileDir)
++ mozilla::Telemetry::WriteFailedProfileLock(aProfileDir);
+
+ rv = xpcom.SetWindowCreator(aNative);
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+@@ -2100,21 +2126,27 @@ ProfileErrorDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
+ static const char16_t kReadOnly[] = MOZ_UTF16("profileReadOnlyMac");
+ #endif
+ static const char16_t kAccessDenied[] = MOZ_UTF16("profileAccessDenied");
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ static const char16_t kMigrationFailed[] = MOZ_UTF16("profileMigrationFailed");
++#endif
+
+ const char16_t* errorKey = aUnlocker ? kRestartUnlocker
+ : kRestartNoUnlocker;
++ const char16_t* titleKey = MOZ_UTF16("profileProblemTitle");
+ if (PROFILE_STATUS_READ_ONLY == aStatus)
+ errorKey = kReadOnly;
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ else if (PROFILE_STATUS_MIGRATION_FAILED == aStatus)
++ errorKey = kMigrationFailed;
++#endif
+ else if (PROFILE_STATUS_ACCESS_DENIED == aStatus)
+ errorKey = kAccessDenied;
++ else
++ titleKey = MOZ_UTF16("restartTitle");
++
+ GetFormattedString(overrideSB, sb, errorKey, params, 2,
+ getter_Copies(killMessage));
+
+- const char16_t* titleKey = ((PROFILE_STATUS_READ_ONLY == aStatus) ||
+- (PROFILE_STATUS_ACCESS_DENIED == aStatus))
+- ? MOZ_UTF16("profileProblemTitle")
+- : MOZ_UTF16("restartTitle");
+-
+ nsXPIDLString killTitle;
+ GetFormattedString(overrideSB, sb, titleKey, params, 1,
+ getter_Copies(killTitle));
+@@ -2158,7 +2190,8 @@ ProfileErrorDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
+ }
+ } else {
+ #ifdef MOZ_WIDGET_ANDROID
+- if (mozilla::widget::GeckoAppShell::UnlockProfile()) {
++ if (aProfileDir && aProfileLocalDir && aResult &&
++ mozilla::widget::GeckoAppShell::UnlockProfile()) {
+ return NS_LockProfilePath(aProfileDir, aProfileLocalDir,
+ nullptr, aResult);
+ }
+@@ -2449,6 +2482,223 @@ static ProfileStatus CheckProfileWriteAccess(nsIToolkitProfile* aProfile)
+ return CheckProfileWriteAccess(profileDir);
+ }
+
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++// Obtain an nsIFile for the app root directory, e.g., TorBrowser.app on
++// Mac OS and the directory that contains Browser/ on Linux and Windows.
++static nsresult GetAppRootDir(nsIFile *aAppDir, nsIFile **aAppRootDir)
++{
++ NS_ENSURE_ARG_POINTER(aAppDir);
++
++#ifdef XP_MACOSX
++ nsCOMPtr<nsIFile> tmpDir;
++ nsresult rv = aAppDir->GetParent(getter_AddRefs(tmpDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ return tmpDir->GetParent(aAppRootDir);
++#else
++ return aAppDir->Clone(aAppRootDir);
++#endif
++}
++
++static ProfileStatus CheckTorBrowserDataWriteAccess(nsIFile *aAppDir)
++{
++ // Check whether we can write to the directory that will contain
++ // TorBrowser-Data.
++ nsCOMPtr<nsIFile> tbDataDir;
++ nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton();
++ if (!dirProvider)
++ return PROFILE_STATUS_OTHER_ERROR;
++ nsresult rv =
++ dirProvider->GetTorBrowserUserDataDir(getter_AddRefs(tbDataDir));
++ NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
++ nsCOMPtr<nsIFile> tbDataDirParent;
++ rv = tbDataDir->GetParent(getter_AddRefs(tbDataDirParent));
++ NS_ENSURE_SUCCESS(rv, PROFILE_STATUS_OTHER_ERROR);
++ return CheckProfileWriteAccess(tbDataDirParent);
++}
++
++// Move the directory defined by combining aSrcParentDir and aSrcRelativePath
++// to the location defined by combining aDestParentDir and aDestRelativePath.
++// If the source directory does not exist, no changes are made and NS_OK is
++// returned.
++// If the destination directory exists, its contents are removed after the
++// source directory has been moved (if the move fails for some reason, the
++// original contents of the destination directory are restored).
++static nsresult
++migrateOneTorBrowserDataDir(nsIFile *aSrcParentDir,
++ const nsACString &aSrcRelativePath,
++ nsIFile *aDestParentDir,
++ const nsACString &aDestRelativePath)
++{
++ NS_ENSURE_ARG_POINTER(aSrcParentDir);
++ NS_ENSURE_ARG_POINTER(aDestParentDir);
++
++ nsCOMPtr<nsIFile> srcDir;
++ nsresult rv = aSrcParentDir->Clone(getter_AddRefs(srcDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ if (!aSrcRelativePath.IsEmpty()) {
++ rv = srcDir->AppendRelativeNativePath(aSrcRelativePath);
++ NS_ENSURE_SUCCESS(rv, rv);
++ }
++
++ bool srcDirExists = false;
++ srcDir->Exists(&srcDirExists);
++ if (!srcDirExists)
++ return NS_OK; // Old data does not exist; skip migration.
++
++ nsCOMPtr<nsIFile> destDir;
++ rv = aDestParentDir->Clone(getter_AddRefs(destDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ if (!aDestRelativePath.IsEmpty()) {
++ rv = destDir->AppendRelativeNativePath(aDestRelativePath);
++ NS_ENSURE_SUCCESS(rv, rv);
++ }
++
++ nsCOMPtr<nsIFile> destParentDir;
++ rv = destDir->GetParent(getter_AddRefs(destParentDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ nsAutoString destLeafName;
++ rv = destDir->GetLeafName(destLeafName);
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ bool destDirExists = false;
++ destDir->Exists(&destDirExists);
++ nsCOMPtr<nsIFile> tmpDir;
++ if (destDirExists) {
++ // The destination directory exists. When we are migrating an old
++ // Tor Browser profile, we expect this to be the case because we first
++ // allow the standard Mozilla startup code to create a new profile as
++ // usual, and then later (here) we set aside that profile directory and
++ // replace it with the old Tor Browser profile that we need to migrate.
++ // For now, move the Mozilla profile directory aside and set tmpDir to
++ // point to its new, temporary location in case migration fails and we
++ // need to restore the profile that was created by the Mozilla code.
++ nsAutoString tmpName(NS_LITERAL_STRING("tmp"));
++ rv = destDir->RenameTo(nullptr, tmpName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ nsCOMPtr<nsIFile> dir;
++ rv = destParentDir->Clone(getter_AddRefs(dir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = dir->Append(tmpName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ tmpDir = dir;
++ }
++
++ // Move the old directory to the new location using MoveTo() so that
++ // timestamps are preserved (MoveTo() is atomic as long as the source and
++ // destination are on the same volume).
++ rv = srcDir->MoveTo(destParentDir, destLeafName);
++ if (NS_FAILED(rv)) {
++ // The move failed. Restore the directory that we were trying to replace.
++ if (tmpDir)
++ tmpDir->RenameTo(nullptr, destLeafName);
++ return rv;
++ }
++
++ // Success. If we set aside a directory earlier by renaming it, remove it.
++ if (tmpDir)
++ tmpDir->Remove(true);
++
++ return NS_OK;
++}
++
++static nsresult
++deleteFile(nsIFile *aParentDir, const nsACString &aRelativePath)
++{
++ NS_ENSURE_ARG_POINTER(aParentDir);
++
++ nsCOMPtr<nsIFile> file;
++ nsresult rv = aParentDir->Clone(getter_AddRefs(file));
++ NS_ENSURE_SUCCESS(rv, rv);
++ if (!aRelativePath.IsEmpty()) {
++ rv = file->AppendRelativeNativePath(aRelativePath);
++ NS_ENSURE_SUCCESS(rv, rv);
++ }
++
++ return file->Remove(false);
++}
++
++// When this function is called, aProfile is a brand new profile and
++// aAppDir is the directory that contains the firefox executable.
++// Our strategy is to check if an old "in application" profile exists at
++// <AppRootDir>/TorBrowser/Data/Browser/profile.default. If so, we set
++// aside the new profile directory and replace it with the old one.
++// We use a similar approach for the Tor data and UpdateInfo directories.
++static nsresult
++migrateInAppTorBrowserProfile(nsIToolkitProfile *aProfile, nsIFile *aAppDir)
++{
++ NS_ENSURE_ARG_POINTER(aProfile);
++ NS_ENSURE_ARG_POINTER(aAppDir);
++
++ nsCOMPtr<nsIFile> appRootDir;
++ nsresult rv = GetAppRootDir(aAppDir, getter_AddRefs(appRootDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ // Create an nsIFile for the old <AppRootDir>/TorBrowser directory.
++ nsCOMPtr<nsIFile> oldTorBrowserDir;
++ rv = appRootDir->Clone(getter_AddRefs(oldTorBrowserDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = oldTorBrowserDir->AppendRelativeNativePath(
++ NS_LITERAL_CSTRING("TorBrowser"));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ // Get an nsIFile for the TorBrowser-Data directory.
++ nsCOMPtr<nsIFile> newTBDataDir;
++ nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton();
++ if (!dirProvider)
++ return NS_ERROR_UNEXPECTED;
++ rv = dirProvider->GetTorBrowserUserDataDir(getter_AddRefs(newTBDataDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ // Try to migrate the browser profile. If this fails, we return an error
++ // code and we do not try to migrate any other data.
++ nsCOMPtr<nsIFile> newProfileDir;
++ rv = aProfile->GetRootDir(getter_AddRefs(newProfileDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ nsAutoCString path(NS_LITERAL_CSTRING("Data" XPCOM_FILE_PATH_SEPARATOR
++ "Browser" XPCOM_FILE_PATH_SEPARATOR "profile.default"));
++ rv = migrateOneTorBrowserDataDir(oldTorBrowserDir, path,
++ newProfileDir, NS_LITERAL_CSTRING(""));
++ NS_ENSURE_SUCCESS(rv, rv); // Return immediately upon failure.
++
++ // Try to migrate the Tor data directory but do not return upon failure.
++ nsAutoCString torDataDirPath(NS_LITERAL_CSTRING("Data"
++ XPCOM_FILE_PATH_SEPARATOR "Tor"));
++ rv = migrateOneTorBrowserDataDir(oldTorBrowserDir, torDataDirPath,
++ newTBDataDir, NS_LITERAL_CSTRING("Tor"));
++ if (NS_SUCCEEDED(rv)) {
++ // Make a "best effort" attempt to remove the Tor data files that should
++ // no longer be stored in the Tor user data directory (they have been
++ // relocated to a read-only Tor directory, e.g.,
++ // TorBrowser.app/Contents/Resources/TorBrowser/Tor.
++ deleteFile(newTBDataDir,
++ NS_LITERAL_CSTRING("Tor" XPCOM_FILE_PATH_SEPARATOR "geoip"));
++ deleteFile(newTBDataDir,
++ NS_LITERAL_CSTRING("Tor" XPCOM_FILE_PATH_SEPARATOR "geoip6"));
++ deleteFile(newTBDataDir,
++ NS_LITERAL_CSTRING("Tor" XPCOM_FILE_PATH_SEPARATOR "torrc-defaults"));
++ }
++
++ // Try to migrate the UpdateInfo directory.
++ nsCOMPtr<nsIFile> newUpdateInfoDir;
++ nsresult rv2 = dirProvider->GetUpdateRootDir(
++ getter_AddRefs(newUpdateInfoDir));
++ if (NS_SUCCEEDED(rv2)) {
++ nsAutoCString updateInfoPath(NS_LITERAL_CSTRING("UpdateInfo"));
++ rv2 = migrateOneTorBrowserDataDir(oldTorBrowserDir, updateInfoPath,
++ newUpdateInfoDir, NS_LITERAL_CSTRING(""));
++ }
++
++ // If all pieces of the migration succeeded, remove the old TorBrowser
++ // directory.
++ if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2)) {
++ oldTorBrowserDir->Remove(true);
++ }
++
++ return NS_OK;
++}
++#endif
++
+ static bool gDoMigration = false;
+ static bool gDoProfileReset = false;
+
+@@ -2461,7 +2711,8 @@ static bool gDoProfileReset = false;
+ // 5) if there are *no* profiles, set up profile-migration
+ // 6) display the profile-manager UI
+ static nsresult
+-SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, nsINativeAppSupport* aNative,
++SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc,
++ nsIFile *aAppDir, nsINativeAppSupport* aNative,
+ bool* aStartOffline, nsACString* aProfileName)
+ {
+ StartupTimeline::Record(StartupTimeline::SELECT_PROFILE);
+@@ -2742,6 +2993,20 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
+ aProfileSvc->SetDefaultProfile(profile);
+ #endif
+ aProfileSvc->Flush();
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ // Handle migration from an older version of Tor Browser in which the
++ // user data was stored inside the application directory.
++ rv = migrateInAppTorBrowserProfile(profile, aAppDir);
++ if (!NS_SUCCEEDED(rv)) {
++ // Display an error alert and continue startup. Since XPCOM was
++ // initialized in a limited way inside ProfileErrorDialog() and
++ // because it cannot be reinitialized, use LaunchChild() to start
++ // the browser.
++ ProfileErrorDialog(profile, PROFILE_STATUS_MIGRATION_FAILED, nullptr,
++ aNative, aResult);
++ return LaunchChild(aNative);
++ }
++#endif
+ rv = profile->Lock(nullptr, aResult);
+ if (NS_SUCCEEDED(rv)) {
+ if (aProfileName)
+@@ -3313,6 +3578,14 @@ XREMain::XRE_mainInit(bool* aExitFlag)
+ NS_BREAK();
+ #endif
+
++#if defined(XP_MACOSX) && defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++ bool hideDockIcon = (CheckArg("invisible") == ARG_FOUND);
++ if (hideDockIcon) {
++ ProcessSerialNumber psn = { 0, kCurrentProcess };
++ TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
++ }
++#endif
++
+ #ifdef USE_GLX_TEST
+ // bug 639842 - it's very important to fire this process BEFORE we set up
+ // error handling. indeed, this process is expected to be crashy, and we
+@@ -4073,6 +4346,22 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
+ #endif
+
+ rv = NS_NewToolkitProfileService(getter_AddRefs(mProfileSvc));
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ if (NS_FAILED(rv)) {
++ // NS_NewToolkitProfileService() returns a generic NS_ERROR_FAILURE error
++ // if creation of the TorBrowser-Data directory fails due to access denied
++ // or because of a read-only disk volume. Do an extra check here to detect
++ // these errors so we can display an informative error message.
++ ProfileStatus status = CheckTorBrowserDataWriteAccess(exeDir);
++ if ((PROFILE_STATUS_ACCESS_DENIED == status) ||
++ (PROFILE_STATUS_READ_ONLY == status)) {
++ ProfileErrorDialog(nullptr, nullptr, status, nullptr, mNativeApp,
++ nullptr);
++ return 1;
++ }
++ }
++#endif
++
+ if (rv == NS_ERROR_FILE_ACCESS_DENIED) {
+ PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \
+ "your profile directory.\n");
+@@ -4083,8 +4372,8 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
+ return 1;
+ }
+
+- rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, mNativeApp, &mStartOffline,
+- &mProfileName);
++ rv = SelectProfile(getter_AddRefs(mProfileLock), mProfileSvc, exeDir,
++ mNativeApp, &mStartOffline, &mProfileName);
+ if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
+ rv == NS_ERROR_ABORT) {
+ *aExitFlag = true;
+diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
+index 403e820..e3c1449 100644
+--- a/toolkit/xre/nsXREDirProvider.cpp
++++ b/toolkit/xre/nsXREDirProvider.cpp
+@@ -38,6 +38,8 @@
+ #include "mozilla/Preferences.h"
+ #include "mozilla/Telemetry.h"
+
++#include "TorFileUtils.h"
++
+ #include <stdlib.h>
+
+ #ifdef XP_WIN
+@@ -1057,40 +1059,48 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
+ getter_AddRefs(updRoot));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+-#else
++#elif defined(TOR_BROWSER_UPDATE)
++ // For Tor Browser, we store update history, etc. within the UpdateInfo
++ // directory under the user data directory.
++ nsresult rv = GetTorBrowserUserDataDir(getter_AddRefs(updRoot));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = updRoot->AppendNative(NS_LITERAL_CSTRING("UpdateInfo"));
++ NS_ENSURE_SUCCESS(rv, rv);
++#if defined(XP_MACOSX) && defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++ // Since the TorBrowser-Data directory may be shared among different
++ // installations of the application, embed the app path in the update dir
++ // so that the update history is partitioned. This is much less likely to
++ // be an issue on Linux or Windows because the Tor Browser packages for
++ // those platforms include a "container" folder that provides partitioning
++ // by default, and we do not support use of a shared, OS-recommended area
++ // for user data on those platforms.
+ nsCOMPtr<nsIFile> appFile;
+ bool per = false;
+- nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
+- NS_ENSURE_SUCCESS(rv, rv);
+- rv = appFile->GetParent(getter_AddRefs(updRoot));
++ rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
+ NS_ENSURE_SUCCESS(rv, rv);
++ nsCOMPtr<nsIFile> appRootDirFile;
++ nsAutoString appDirPath;
++ if (NS_FAILED(appFile->GetParent(getter_AddRefs(appRootDirFile))) ||
++ NS_FAILED(appRootDirFile->GetPath(appDirPath))) {
++ return NS_ERROR_FAILURE;
++ }
+
+-#ifdef XP_MACOSX
+-#ifdef TOR_BROWSER_UPDATE
+-#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
+- // For Tor Browser, we cannot store update history, etc. under the user's
+- // home directory. Instead, we place it under
+- // Tor Browser.app/../TorBrowser-Data/UpdateInfo/
+- nsCOMPtr<nsIFile> appRootDir;
+- rv = GetAppRootDir(getter_AddRefs(appRootDir));
+- NS_ENSURE_SUCCESS(rv, rv);
+- nsCOMPtr<nsIFile> localDir;
+- rv = appRootDir->GetParent(getter_AddRefs(localDir));
+- NS_ENSURE_SUCCESS(rv, rv);
+- rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser-Data"
+- XPCOM_FILE_PATH_SEPARATOR "UpdateInfo"));
+-#else
+- // For Tor Browser, we cannot store update history, etc. under the user's home directory.
+- // Instead, we place it under Tor Browser.app/TorBrowser/UpdateInfo/
+- nsCOMPtr<nsIFile> localDir;
+- rv = GetAppRootDir(getter_AddRefs(localDir));
+- NS_ENSURE_SUCCESS(rv, rv);
+- rv = localDir->AppendNative(NS_LITERAL_CSTRING("TorBrowser"));
++ int32_t dotIndex = appDirPath.RFind(".app");
++ if (dotIndex == kNotFound) {
++ dotIndex = appDirPath.Length();
++ }
++ appDirPath = Substring(appDirPath, 1, dotIndex - 1);
++ rv = updRoot->AppendRelativePath(appDirPath);
+ NS_ENSURE_SUCCESS(rv, rv);
+- rv = localDir->AppendNative(NS_LITERAL_CSTRING("UpdateInfo"));
+ #endif
++#else // ! TOR_BROWSER_UPDATE
++ nsCOMPtr<nsIFile> appFile;
++ bool per = false;
++ nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+-#else
++ rv = appFile->GetParent(getter_AddRefs(updRoot));
++ NS_ENSURE_SUCCESS(rv, rv);
++#ifdef XP_MACOSX
+ nsCOMPtr<nsIFile> appRootDirFile;
+ nsCOMPtr<nsIFile> localDir;
+ nsAutoString appDirPath;
+@@ -1121,7 +1131,6 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
+ NS_FAILED(localDir->AppendRelativePath(appDirPath))) {
+ return NS_ERROR_FAILURE;
+ }
+-#endif
+
+ localDir.forget(aResult);
+ return NS_OK;
+@@ -1215,7 +1224,7 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ #endif // XP_WIN
+-#endif
++#endif // ! TOR_BROWSER_UPDATE
+ updRoot.forget(aResult);
+ return NS_OK;
+ }
+@@ -1268,12 +1277,15 @@ nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal)
+ // Copied from nsAppFileLocationProvider (more or less)
+ NS_ENSURE_ARG_POINTER(aFile);
+ nsCOMPtr<nsIFile> localDir;
+-
+- nsresult rv = GetAppRootDir(getter_AddRefs(localDir));
++ nsresult rv = GetTorBrowserUserDataDir(getter_AddRefs(localDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+- rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser"
+- XPCOM_FILE_PATH_SEPARATOR "Data"
++
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Browser"));
++#else
++ rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("Data"
+ XPCOM_FILE_PATH_SEPARATOR "Browser"));
++#endif
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aLocal) {
+@@ -1377,43 +1389,16 @@ nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal,
+ }
+
+ nsresult
+-nsXREDirProvider::GetAppRootDir(nsIFile* *aFile)
++nsXREDirProvider::GetTorBrowserUserDataDir(nsIFile* *aFile)
+ {
+ NS_ENSURE_ARG_POINTER(aFile);
+- nsCOMPtr<nsIFile> appRootDir;
+-
+- nsresult rv = GetAppDir()->Clone(getter_AddRefs(appRootDir));
++ nsCOMPtr<nsIFile> exeFile;
++ bool per = false;
++ nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(exeFile));
+ NS_ENSURE_SUCCESS(rv, rv);
+-
+- int levelsToRemove = 0; // In FF21+, appDir points to browser subdirectory.
+-#if defined(XP_MACOSX)
+- levelsToRemove += 1;
+-#endif
+- while (appRootDir && (levelsToRemove > 0)) {
+- // When crawling up the hierarchy, components named "." do not count.
+- nsAutoCString removedName;
+- rv = appRootDir->GetNativeLeafName(removedName);
+- NS_ENSURE_SUCCESS(rv, rv);
+- bool didRemove = !removedName.Equals(".");
+-
+- // Remove a directory component.
+- nsCOMPtr<nsIFile> parentDir;
+- rv = appRootDir->GetParent(getter_AddRefs(parentDir));
+- NS_ENSURE_SUCCESS(rv, rv);
+- appRootDir = parentDir;
+-
+- if (didRemove)
+- --levelsToRemove;
+- }
+-
+- if (!appRootDir)
+- return NS_ERROR_FAILURE;
+-
+- appRootDir.forget(aFile);
+- return NS_OK;
++ return TorBrowser_GetUserDataDir(exeFile, aFile);
+ }
+
+-
+ nsresult
+ nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
+ {
+diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h
+index b86cc68..e8190e3 100644
+--- a/toolkit/xre/nsXREDirProvider.h
++++ b/toolkit/xre/nsXREDirProvider.h
+@@ -100,6 +100,12 @@ public:
+ */
+ nsresult GetProfileDir(nsIFile* *aResult);
+
++ /**
++ * Get the TorBrowser user data directory by calling the
++ * TorBrowser_GetUserDataDir() utility function.
++ */
++ nsresult GetTorBrowserUserDataDir(nsIFile* *aFile);
++
+ protected:
+ nsresult GetFilesInternal(const char* aProperty, nsISimpleEnumerator** aResult);
+ nsresult GetUserDataDirectoryHome(nsIFile* *aFile, bool aLocal);
+@@ -107,7 +113,6 @@ protected:
+ #if defined(XP_UNIX) || defined(XP_MACOSX)
+ static nsresult GetSystemExtensionsDirectory(nsIFile** aFile);
+ #endif
+- nsresult GetAppRootDir(nsIFile* *aFile);
+ static nsresult EnsureDirectoryExists(nsIFile* aDirectory);
+ void EnsureProfileFileExists(nsIFile* aFile);
+
+diff --git a/xpcom/io/TorFileUtils.cpp b/xpcom/io/TorFileUtils.cpp
+new file mode 100644
+index 0000000..2b0b100
+--- /dev/null
++++ b/xpcom/io/TorFileUtils.cpp
+@@ -0,0 +1,130 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* 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 "TorFileUtils.h"
++
++static nsresult GetAppRootDir(nsIFile *aExeFile, nsIFile** aFile);
++
++//-----------------------------------------------------------------------------
++NS_METHOD
++TorBrowser_GetUserDataDir(nsIFile *aExeFile, nsIFile** aFile)
++{
++ NS_ENSURE_ARG_POINTER(aFile);
++ nsCOMPtr<nsIFile> tbDataDir;
++
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ nsAutoCString tbDataLeafName(NS_LITERAL_CSTRING("TorBrowser-Data"));
++ nsCOMPtr<nsIFile> appRootDir;
++ nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(appRootDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++#ifndef XP_MACOSX
++ // On all platforms except Mac OS, we always operate in a "portable" mode
++ // where the TorBrowser-Data directory is located next to the application.
++ rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = tbDataDir->AppendNative(tbDataLeafName);
++ NS_ENSURE_SUCCESS(rv, rv);
++#else
++ // For Mac OS, determine whether we should store user data in the OS's
++ // standard location (i.e., under ~/Library/Application Support). We use
++ // the OS location if (1) the application is installed in a directory whose
++ // path contains "/Applications" or (2) the TorBrowser-Data directory does
++ // not exist and cannot be created (which probably means we lack write
++ // permission to the directory that contains the application).
++ nsAutoString appRootPath;
++ rv = appRootDir->GetPath(appRootPath);
++ NS_ENSURE_SUCCESS(rv, rv);
++ bool useOSLocation = (appRootPath.Find("/Applications",
++ true /* ignore case */) >= 0);
++ if (!useOSLocation) {
++ // We hope to use the portable (aka side-by-side) approach, but before we
++ // commit to that, let's ensure that we can create the TorBrowser-Data
++ // directory. If it already exists, we will try to use it; if not and we
++ // fail to create it, we will switch to ~/Library/Application Support.
++ rv = appRootDir->GetParent(getter_AddRefs(tbDataDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = tbDataDir->AppendNative(tbDataLeafName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ bool exists = false;
++ rv = tbDataDir->Exists(&exists);
++ if (NS_SUCCEEDED(rv) && !exists)
++ rv = tbDataDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
++ useOSLocation = NS_FAILED(rv);
++ }
++
++ if (useOSLocation) {
++ // We are using ~/Library/Application Support/TorBrowser-Data. We do not
++ // need to create that directory here because the code in nsXREDirProvider
++ // will do so (and the user should always have write permission for
++ // ~/Library/Application Support; if they do not we have no more options).
++ FSRef fsRef;
++ OSErr err = ::FSFindFolder(kUserDomain, kApplicationSupportFolderType,
++ kCreateFolder, &fsRef);
++ NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
++ // To convert the FSRef returned by FSFindFolder() into an nsIFile that
++ // points to ~/Library/Application Support, we first create an empty
++ // nsIFile object (no path) and then use InitWithFSRef() to set the
++ // path.
++ rv = NS_NewNativeLocalFile(EmptyCString(), true,
++ getter_AddRefs(tbDataDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(tbDataDir);
++ if (!dirFileMac)
++ return NS_ERROR_UNEXPECTED;
++ rv = dirFileMac->InitWithFSRef(&fsRef);
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = tbDataDir->AppendNative(tbDataLeafName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ }
++#endif
++
++#else
++ // User data is embedded within the application directory (i.e.,
++ // TOR_BROWSER_DATA_OUTSIDE_APP_DIR is not defined).
++ nsresult rv = GetAppRootDir(aExeFile, getter_AddRefs(tbDataDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = tbDataDir->AppendNative(NS_LITERAL_CSTRING("TorBrowser"));
++ NS_ENSURE_SUCCESS(rv, rv);
++#endif
++
++ tbDataDir.forget(aFile);
++ return NS_OK;
++}
++
++static nsresult
++GetAppRootDir(nsIFile *aExeFile, nsIFile** aFile)
++{
++ NS_ENSURE_ARG_POINTER(aExeFile);
++ NS_ENSURE_ARG_POINTER(aFile);
++ nsCOMPtr<nsIFile> appRootDir = aExeFile;
++
++ int levelsToRemove = 0; // Remove firefox (the executable file).
++#if defined(XP_MACOSX)
++ levelsToRemove += 1; // On Mac OS, we must also remove Contents/MacOS.
++#endif
++ while (appRootDir && (levelsToRemove > 0)) {
++ // When crawling up the hierarchy, components named "." do not count.
++ nsAutoCString removedName;
++ nsresult rv = appRootDir->GetNativeLeafName(removedName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ bool didRemove = !removedName.Equals(".");
++
++ // Remove a directory component.
++ nsCOMPtr<nsIFile> parentDir;
++ rv = appRootDir->GetParent(getter_AddRefs(parentDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ appRootDir = parentDir;
++
++ if (didRemove)
++ --levelsToRemove;
++ }
++
++ if (!appRootDir)
++ return NS_ERROR_FAILURE;
++
++ appRootDir.forget(aFile);
++ return NS_OK;
++}
+diff --git a/xpcom/io/TorFileUtils.h b/xpcom/io/TorFileUtils.h
+new file mode 100644
+index 0000000..293ed04
+--- /dev/null
++++ b/xpcom/io/TorFileUtils.h
+@@ -0,0 +1,35 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=8 sts=2 et sw=2 tw=80: */
++/* 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 TorFileUtils_h__
++#define TorFileUtils_h__
++
++#include "nsIFile.h"
++
++class nsIFile;
++
++/**
++ * TorBrowser_GetUserDataDir
++ *
++ * Retrieve the Tor Browser user data directory.
++ * When built with --enable-tor-browser-data-outside-app-dir, the directory
++ * is next to the application directory, except on Mac OS where it may be
++ * there or it may be at ~/Library/Application Support/TorBrowser-Data (the
++ * latter location is used if the .app bundle is in a directory whose path
++ * contains /Applications or if we lack write access to the directory that
++ * contains the .app).
++ * When built without --enable-tor-browser-data-outside-app-dir, this
++ * directory is TorBrowser.app/TorBrowser.
++ *
++ * @param aExeFile The firefox executable.
++ * @param aFile Out parameter that is set to the Tor Browser user data
++ * directory.
++ * @return NS_OK on success. Error otherwise.
++ */
++extern NS_METHOD
++TorBrowser_GetUserDataDir(nsIFile *aExeFile, nsIFile** aFile);
++
++#endif // !TorFileUtils_h__
+diff --git a/xpcom/io/moz.build b/xpcom/io/moz.build
+index bc62f71..c90f33c 100644
+--- a/xpcom/io/moz.build
++++ b/xpcom/io/moz.build
+@@ -80,6 +80,7 @@ EXPORTS += [
+ 'nsUnicharInputStream.h',
+ 'nsWildCard.h',
+ 'SpecialSystemDirectory.h',
++ 'TorFileUtils.h',
+ ]
+
+ EXPORTS.mozilla += [
+@@ -116,6 +117,7 @@ UNIFIED_SOURCES += [
+ 'SnappyFrameUtils.cpp',
+ 'SnappyUncompressInputStream.cpp',
+ 'SpecialSystemDirectory.cpp',
++ 'TorFileUtils.cpp',
+ ]
+
+ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp
+index 039a89e..da66b90 100644
+--- a/xpcom/io/nsAppFileLocationProvider.cpp
++++ b/xpcom/io/nsAppFileLocationProvider.cpp
+@@ -29,6 +29,7 @@
+ #include <sys/param.h>
+ #endif
+
++#include "TorFileUtils.h"
+
+ // WARNING: These hard coded names need to go away. They need to
+ // come from localizable resources
+@@ -282,8 +283,14 @@ nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile)
+ //----------------------------------------------------------------------------------------
+ // GetProductDirectory - Gets the directory which contains the application data folder
+ //
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++// UNIX and WIN : <App Folder>/../TorBrowser-Data/Browser
++// Mac : <App Folder>/../../../TorBrowser-Data/Browser OR
++// ~/Library/Application Support/TorBrowser-Data/Browser
++#else
+ // UNIX and WIN : <App Folder>/TorBrowser/Data/Browser
+ // Mac : <App Folder>/../../TorBrowser/Data/Browser
++#endif
+ //----------------------------------------------------------------------------------------
+ NS_METHOD
+ nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
+@@ -293,42 +300,25 @@ nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
+ return NS_ERROR_INVALID_ARG;
+ }
+
+- nsresult rv;
++ nsresult rv = NS_ERROR_UNEXPECTED;
+ bool exists;
+- nsCOMPtr<nsIFile> localDir;
++ nsCOMPtr<nsIFile> localDir, exeFile;
+
+- rv = CloneMozBinDirectory(getter_AddRefs(localDir));
++ nsCOMPtr<nsIProperties> directoryService(
++ do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = directoryService->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
++ getter_AddRefs(exeFile));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = TorBrowser_GetUserDataDir(exeFile, getter_AddRefs(localDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+- int levelsToRemove = 0; // In FF21+, bin dir points to browser subdirectory.
+-#if defined(XP_MACOSX)
+- levelsToRemove += 1;
+-#endif
+- while (localDir && (levelsToRemove > 0)) {
+- // When crawling up the hierarchy, components named "." do not count.
+- nsAutoCString removedName;
+- rv = localDir->GetNativeLeafName(removedName);
+- NS_ENSURE_SUCCESS(rv, rv);
+- bool didRemove = !removedName.Equals(".");
+-
+- // Remove a directory component.
+- nsCOMPtr<nsIFile> parentDir;
+- rv = localDir->GetParent(getter_AddRefs(parentDir));
+- NS_ENSURE_SUCCESS(rv, rv);
+- localDir = parentDir;
+-
+- if (didRemove) {
+- --levelsToRemove;
+- }
+- }
+-
+- if (!localDir) {
+- return NS_ERROR_FAILURE;
+- }
+-
+- rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser"
+- XPCOM_FILE_PATH_SEPARATOR "Data"
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Browser"));
++#else
++ rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("Data"
+ XPCOM_FILE_PATH_SEPARATOR "Browser"));
++#endif
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aLocal) {
+--
+cgit v0.10.2
+
1
0

[tor-messenger-build/master] Replace Firefox with Instantbird in aboutDialog.js
by arlo@torproject.org 28 Jul '16
by arlo@torproject.org 28 Jul '16
28 Jul '16
commit af33c3fef7e05c4330b2decb7702639c4d71e564
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Mon Jul 18 22:12:45 2016 -0400
Replace Firefox with Instantbird in aboutDialog.js
---
projects/instantbird/aboutDialog.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/projects/instantbird/aboutDialog.js b/projects/instantbird/aboutDialog.js
index 25b2793..9cfecd1 100644
--- a/projects/instantbird/aboutDialog.js
+++ b/projects/instantbird/aboutDialog.js
@@ -56,7 +56,7 @@ function init(aEvent)
let versionElem = document.getElementById("version");
if (versionElem) {
versionElem.textContent = TOR_BROWSER_VERSION +
- " (based on Mozilla Firefox " +
+ " (based on Instantbird " +
versionElem.textContent + ")";
}
#endif
1
0

[tor-messenger-build/master] Update patch for #9173 and add patch for #4234 (Firefox update)
by arlo@torproject.org 28 Jul '16
by arlo@torproject.org 28 Jul '16
28 Jul '16
commit 770a2829ba7a84bc0ed910b6ce503d152221f684
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Mon Jul 18 12:36:28 2016 -0400
Update patch for #9173 and add patch for #4234 (Firefox update)
---
...ault-Firefox-profile-director-bug-9173.mozpatch | 451 ++++
.../Firefox-update-process-bug-4234.mozpatch | 2156 ++++++++++++++++++++
2 files changed, 2607 insertions(+)
diff --git a/projects/instantbird/Change-the-default-Firefox-profile-director-bug-9173.mozpatch b/projects/instantbird/Change-the-default-Firefox-profile-director-bug-9173.mozpatch
new file mode 100644
index 0000000..4447c70
--- /dev/null
+++ b/projects/instantbird/Change-the-default-Firefox-profile-director-bug-9173.mozpatch
@@ -0,0 +1,451 @@
+From 48068e88b66ba37c725850331d099f10f9d34c90 Mon Sep 17 00:00:00 2001
+From: Kathy Brade <brade(a)pearlcrescent.com>
+Date: Fri, 18 Oct 2013 15:20:06 -0400
+Subject: Bug #9173: Change the default Firefox profile directory to be
+ TBB-relative.
+
+This should eliminate our need to rely on a wrapper script that
+sets $HOME and launches Firefox with -profile.
+
+diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
+index a828d33..831a373 100644
+--- a/toolkit/xre/nsXREDirProvider.cpp
++++ b/toolkit/xre/nsXREDirProvider.cpp
+@@ -32,6 +32,7 @@
+ #include "nsArrayEnumerator.h"
+ #include "nsEnumeratorUtils.h"
+ #include "nsReadableUtils.h"
++#include "nsXPCOMPrivate.h" // for XPCOM_FILE_PATH_SEPARATOR
+ #include "mozilla/Services.h"
+ #include "mozilla/Omnijar.h"
+ #include "mozilla/Preferences.h"
+@@ -200,9 +201,6 @@ nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult,
+ aProfileName, aAppName, aVendorName);
+
+ if (NS_SUCCEEDED(rv)) {
+-#if !defined(XP_UNIX) || defined(XP_MACOSX)
+- rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
+-#endif
+ // We must create the profile directory here if it does not exist.
+ nsresult tmp = EnsureDirectoryExists(file);
+ if (NS_FAILED(tmp)) {
+@@ -225,9 +223,6 @@ nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult,
+ aProfileName, aAppName, aVendorName);
+
+ if (NS_SUCCEEDED(rv)) {
+-#if !defined(XP_UNIX) || defined(XP_MACOSX)
+- rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles"));
+-#endif
+ // We must create the profile directory here if it does not exist.
+ nsresult tmp = EnsureDirectoryExists(file);
+ if (NS_FAILED(tmp)) {
+@@ -1245,90 +1240,45 @@ nsresult
+ nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal)
+ {
+ // Copied from nsAppFileLocationProvider (more or less)
+- nsresult rv;
++ NS_ENSURE_ARG_POINTER(aFile);
+ nsCOMPtr<nsIFile> localDir;
+
+-#if defined(XP_MACOSX)
+- FSRef fsRef;
+- OSType folderType;
+- if (aLocal) {
+- folderType = kCachedDataFolderType;
+- } else {
+-#ifdef MOZ_THUNDERBIRD
+- folderType = kDomainLibraryFolderType;
+-#else
+- folderType = kApplicationSupportFolderType;
+-#endif
+- }
+- OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
+- NS_ENSURE_FALSE(err, NS_ERROR_FAILURE);
+-
+- rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir));
++ nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+- nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir);
+- NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED);
++ int levelsToRemove = 0; // In FF21+, appDir points to browser subdirectory.
++#if defined(XP_MACOSX)
++ levelsToRemove += 1;
++#endif
++ while (localDir && (levelsToRemove > 0)) {
++ // When crawling up the hierarchy, components named "." do not count.
++ nsAutoCString removedName;
++ rv = localDir->GetNativeLeafName(removedName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ bool didRemove = !removedName.Equals(".");
+
+- rv = dirFileMac->InitWithFSRef(&fsRef);
+- NS_ENSURE_SUCCESS(rv, rv);
++ // Remove a directory component.
++ nsCOMPtr<nsIFile> parentDir;
++ rv = localDir->GetParent(getter_AddRefs(parentDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ localDir = parentDir;
+
+- localDir = do_QueryInterface(dirFileMac, &rv);
+-#elif defined(XP_IOS)
+- nsAutoCString userDir;
+- if (GetUIKitDirectory(aLocal, userDir)) {
+- rv = NS_NewNativeLocalFile(userDir, true, getter_AddRefs(localDir));
+- } else {
+- rv = NS_ERROR_FAILURE;
+- }
+- NS_ENSURE_SUCCESS(rv, rv);
+-#elif defined(XP_WIN)
+- nsString path;
+- if (aLocal) {
+- rv = GetShellFolderPath(CSIDL_LOCAL_APPDATA, path);
+- if (NS_FAILED(rv))
+- rv = GetRegWindowsAppDataFolder(aLocal, path);
+- }
+- if (!aLocal || NS_FAILED(rv)) {
+- rv = GetShellFolderPath(CSIDL_APPDATA, path);
+- if (NS_FAILED(rv)) {
+- if (!aLocal)
+- rv = GetRegWindowsAppDataFolder(aLocal, path);
+- }
++ if (didRemove)
++ --levelsToRemove;
+ }
+- NS_ENSURE_SUCCESS(rv, rv);
+
+- rv = NS_NewLocalFile(path, true, getter_AddRefs(localDir));
+-#elif defined(MOZ_WIDGET_GONK)
+- rv = NS_NewNativeLocalFile(NS_LITERAL_CSTRING("/data/b2g"), true,
+- getter_AddRefs(localDir));
+-#elif defined(XP_UNIX)
+- const char* homeDir = getenv("HOME");
+- if (!homeDir || !*homeDir)
++ if (!localDir)
+ return NS_ERROR_FAILURE;
+
+-#ifdef ANDROID /* We want (ProfD == ProfLD) on Android. */
+- aLocal = false;
+-#endif
++ rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser"
++ XPCOM_FILE_PATH_SEPARATOR "Data"
++ XPCOM_FILE_PATH_SEPARATOR "Browser"));
++ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (aLocal) {
+- // If $XDG_CACHE_HOME is defined use it, otherwise use $HOME/.cache.
+- const char* cacheHome = getenv("XDG_CACHE_HOME");
+- if (cacheHome && *cacheHome) {
+- rv = NS_NewNativeLocalFile(nsDependentCString(cacheHome), true,
+- getter_AddRefs(localDir));
+- } else {
+- rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
+- getter_AddRefs(localDir));
+- if (NS_SUCCEEDED(rv))
+- rv = localDir->AppendNative(NS_LITERAL_CSTRING(".cache"));
+- }
+- } else {
+- rv = NS_NewNativeLocalFile(nsDependentCString(homeDir), true,
+- getter_AddRefs(localDir));
++ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
++ NS_ENSURE_SUCCESS(rv, rv);
+ }
+-#else
+-#error "Don't know how to get product dir on your platform"
+-#endif
+
+ NS_IF_ADDREF(*aFile = localDir);
+ return rv;
+@@ -1541,48 +1491,25 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile,
+ }
+
+ nsAutoCString profile;
+- nsAutoCString appName;
+- nsAutoCString vendor;
+ if (aProfileName && !aProfileName->IsEmpty()) {
+ profile = *aProfileName;
+- } else if (aAppName) {
+- appName = *aAppName;
+- if (aVendorName) {
+- vendor = *aVendorName;
+- }
+ } else if (gAppData->profile) {
+ profile = gAppData->profile;
+- } else {
+- appName = gAppData->name;
+- vendor = gAppData->vendor;
+ }
+
+- nsresult rv;
++ nsresult rv = NS_ERROR_FAILURE;
+
+ #if defined (XP_MACOSX)
+ if (!profile.IsEmpty()) {
+ rv = AppendProfileString(aFile, profile.get());
++ NS_ENSURE_SUCCESS(rv, rv);
+ }
+- else {
+- // Note that MacOS ignores the vendor when creating the profile hierarchy -
+- // all application preferences directories live alongside one another in
+- // ~/Library/Application Support/
+- rv = aFile->AppendNative(appName);
+- }
+- NS_ENSURE_SUCCESS(rv, rv);
+
+ #elif defined(XP_WIN)
+ if (!profile.IsEmpty()) {
+ rv = AppendProfileString(aFile, profile.get());
++ NS_ENSURE_SUCCESS(rv, rv);
+ }
+- else {
+- if (!vendor.IsEmpty()) {
+- rv = aFile->AppendNative(vendor);
+- NS_ENSURE_SUCCESS(rv, rv);
+- }
+- rv = aFile->AppendNative(appName);
+- }
+- NS_ENSURE_SUCCESS(rv, rv);
+
+ #elif defined(ANDROID)
+ // The directory used for storing profiles
+@@ -1594,12 +1521,6 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile,
+ rv = aFile->AppendNative(nsDependentCString("mozilla"));
+ NS_ENSURE_SUCCESS(rv, rv);
+ #elif defined(XP_UNIX)
+- nsAutoCString folder;
+- // Make it hidden (by starting with "."), except when local (the
+- // profile is already under ~/.cache or XDG_CACHE_HOME).
+- if (!aLocal)
+- folder.Assign('.');
+-
+ if (!profile.IsEmpty()) {
+ // Skip any leading path characters
+ const char* profileStart = profile.get();
+@@ -1608,31 +1529,17 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile,
+
+ // On the off chance that someone wanted their folder to be hidden don't
+ // let it become ".."
+- if (*profileStart == '.' && !aLocal)
++ if (*profileStart == '.')
+ profileStart++;
+
++ // Make it hidden (by starting with ".").
++ nsAutoCString folder(".");
+ folder.Append(profileStart);
+ ToLowerCase(folder);
+
+ rv = AppendProfileString(aFile, folder.BeginReading());
++ NS_ENSURE_SUCCESS(rv, rv);
+ }
+- else {
+- if (!vendor.IsEmpty()) {
+- folder.Append(vendor);
+- ToLowerCase(folder);
+-
+- rv = aFile->AppendNative(folder);
+- NS_ENSURE_SUCCESS(rv, rv);
+-
+- folder.Truncate();
+- }
+-
+- folder.Append(appName);
+- ToLowerCase(folder);
+-
+- rv = aFile->AppendNative(folder);
+- }
+- NS_ENSURE_SUCCESS(rv, rv);
+
+ #else
+ #error "Don't know how to get profile path on your platform"
+diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h
+index eb27ed2..1985f66 100644
+--- a/toolkit/xre/nsXREDirProvider.h
++++ b/toolkit/xre/nsXREDirProvider.h
+@@ -56,16 +56,16 @@ public:
+
+ nsresult GetProfileDefaultsDir(nsIFile* *aResult);
+
+- static nsresult GetUserAppDataDirectory(nsIFile* *aFile) {
++ nsresult GetUserAppDataDirectory(nsIFile* *aFile) {
+ return GetUserDataDirectory(aFile, false, nullptr, nullptr, nullptr);
+ }
+- static nsresult GetUserLocalDataDirectory(nsIFile* *aFile) {
++ nsresult GetUserLocalDataDirectory(nsIFile* *aFile) {
+ return GetUserDataDirectory(aFile, true, nullptr, nullptr, nullptr);
+ }
+
+ // By default GetUserDataDirectory gets profile path from gAppData,
+ // but that can be overridden by using aProfileName/aAppName/aVendorName.
+- static nsresult GetUserDataDirectory(nsIFile** aFile, bool aLocal,
++ nsresult GetUserDataDirectory(nsIFile** aFile, bool aLocal,
+ const nsACString* aProfileName,
+ const nsACString* aAppName,
+ const nsACString* aVendorName);
+@@ -102,8 +102,8 @@ public:
+
+ protected:
+ nsresult GetFilesInternal(const char* aProperty, nsISimpleEnumerator** aResult);
+- static nsresult GetUserDataDirectoryHome(nsIFile* *aFile, bool aLocal);
+- static nsresult GetSysUserExtensionsDirectory(nsIFile* *aFile);
++ nsresult GetUserDataDirectoryHome(nsIFile* *aFile, bool aLocal);
++ nsresult GetSysUserExtensionsDirectory(nsIFile* *aFile);
+ #if defined(XP_UNIX) || defined(XP_MACOSX)
+ static nsresult GetSystemExtensionsDirectory(nsIFile** aFile);
+ #endif
+diff --git a/xpcom/io/moz.build b/xpcom/io/moz.build
+index 45732e4..bc62f71 100644
+--- a/xpcom/io/moz.build
++++ b/xpcom/io/moz.build
+@@ -134,4 +134,7 @@ FINAL_LIBRARY = 'xul'
+ if CONFIG['OS_ARCH'] == 'Linux' and 'lib64' in CONFIG['libdir']:
+ DEFINES['HAVE_USR_LIB64_DIR'] = True
+
+-LOCAL_INCLUDES += ['!..']
++LOCAL_INCLUDES += [
++ '!..',
++ '../build',
++]
+diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp
+index 1211c39..039a89e 100644
+--- a/xpcom/io/nsAppFileLocationProvider.cpp
++++ b/xpcom/io/nsAppFileLocationProvider.cpp
+@@ -15,6 +15,7 @@
+ #include "nsISimpleEnumerator.h"
+ #include "prenv.h"
+ #include "nsCRT.h"
++#include "nsXPCOMPrivate.h" // for XPCOM_FILE_PATH_SEPARATOR
+
+ #if defined(MOZ_WIDGET_COCOA)
+ #include <Carbon/Carbon.h>
+@@ -281,9 +282,8 @@ nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile** aLocalFile)
+ //----------------------------------------------------------------------------------------
+ // GetProductDirectory - Gets the directory which contains the application data folder
+ //
+-// UNIX : ~/.mozilla/
+-// WIN : <Application Data folder on user's machine>\Mozilla
+-// Mac : :Documents:Mozilla:
++// UNIX and WIN : <App Folder>/TorBrowser/Data/Browser
++// Mac : <App Folder>/../../TorBrowser/Data/Browser
+ //----------------------------------------------------------------------------------------
+ NS_METHOD
+ nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
+@@ -297,48 +297,45 @@ nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
+ bool exists;
+ nsCOMPtr<nsIFile> localDir;
+
+-#if defined(MOZ_WIDGET_COCOA)
+- FSRef fsRef;
+- OSType folderType = aLocal ? (OSType)kCachedDataFolderType :
+- (OSType)kDomainLibraryFolderType;
+- OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef);
+- if (err) {
+- return NS_ERROR_FAILURE;
++ rv = CloneMozBinDirectory(getter_AddRefs(localDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ int levelsToRemove = 0; // In FF21+, bin dir points to browser subdirectory.
++#if defined(XP_MACOSX)
++ levelsToRemove += 1;
++#endif
++ while (localDir && (levelsToRemove > 0)) {
++ // When crawling up the hierarchy, components named "." do not count.
++ nsAutoCString removedName;
++ rv = localDir->GetNativeLeafName(removedName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ bool didRemove = !removedName.Equals(".");
++
++ // Remove a directory component.
++ nsCOMPtr<nsIFile> parentDir;
++ rv = localDir->GetParent(getter_AddRefs(parentDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ localDir = parentDir;
++
++ if (didRemove) {
++ --levelsToRemove;
++ }
+ }
+- NS_NewLocalFile(EmptyString(), true, getter_AddRefs(localDir));
++
+ if (!localDir) {
+ return NS_ERROR_FAILURE;
+ }
+- nsCOMPtr<nsILocalFileMac> localDirMac(do_QueryInterface(localDir));
+- rv = localDirMac->InitWithFSRef(&fsRef);
+- if (NS_FAILED(rv)) {
+- return rv;
+- }
+-#elif defined(XP_WIN)
+- nsCOMPtr<nsIProperties> directoryService =
+- do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
+- if (NS_FAILED(rv)) {
+- return rv;
+- }
+- const char* prop = aLocal ? NS_WIN_LOCAL_APPDATA_DIR : NS_WIN_APPDATA_DIR;
+- rv = directoryService->Get(prop, NS_GET_IID(nsIFile), getter_AddRefs(localDir));
+- if (NS_FAILED(rv)) {
+- return rv;
+- }
+-#elif defined(XP_UNIX)
+- rv = NS_NewNativeLocalFile(nsDependentCString(PR_GetEnv("HOME")), true,
+- getter_AddRefs(localDir));
+- if (NS_FAILED(rv)) {
+- return rv;
+- }
+-#else
+-#error dont_know_how_to_get_product_dir_on_your_platform
+-#endif
+
+- rv = localDir->AppendRelativeNativePath(DEFAULT_PRODUCT_DIR);
+- if (NS_FAILED(rv)) {
+- return rv;
++ rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser"
++ XPCOM_FILE_PATH_SEPARATOR "Data"
++ XPCOM_FILE_PATH_SEPARATOR "Browser"));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ if (aLocal) {
++ rv = localDir->AppendNative(NS_LITERAL_CSTRING("Caches"));
++ NS_ENSURE_SUCCESS(rv, rv);
+ }
++
+ rv = localDir->Exists(&exists);
+
+ if (NS_SUCCEEDED(rv) && !exists) {
+@@ -357,10 +354,6 @@ nsAppFileLocationProvider::GetProductDirectory(nsIFile** aLocalFile,
+
+ //----------------------------------------------------------------------------------------
+ // GetDefaultUserProfileRoot - Gets the directory which contains each user profile dir
+-//
+-// UNIX : ~/.mozilla/
+-// WIN : <Application Data folder on user's machine>\Mozilla\Profiles
+-// Mac : :Documents:Mozilla:Profiles:
+ //----------------------------------------------------------------------------------------
+ NS_METHOD
+ nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsIFile** aLocalFile,
+@@ -378,23 +371,6 @@ nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsIFile** aLocalFile,
+ return rv;
+ }
+
+-#if defined(MOZ_WIDGET_COCOA) || defined(XP_WIN)
+- // These 3 platforms share this part of the path - do them as one
+- rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("Profiles"));
+- if (NS_FAILED(rv)) {
+- return rv;
+- }
+-
+- bool exists;
+- rv = localDir->Exists(&exists);
+- if (NS_SUCCEEDED(rv) && !exists) {
+- rv = localDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
+- }
+- if (NS_FAILED(rv)) {
+- return rv;
+- }
+-#endif
+-
+ localDir.forget(aLocalFile);
+
+ return rv;
+--
+cgit v0.10.2
+
diff --git a/projects/instantbird/Firefox-update-process-bug-4234.mozpatch b/projects/instantbird/Firefox-update-process-bug-4234.mozpatch
new file mode 100644
index 0000000..a02d80b
--- /dev/null
+++ b/projects/instantbird/Firefox-update-process-bug-4234.mozpatch
@@ -0,0 +1,2156 @@
+From 3f8110f69e1ddfc762a7c7dba4d06b537a785a9c Mon Sep 17 00:00:00 2001
+From: Kathy Brade <brade(a)pearlcrescent.com>
+Date: Thu, 4 Sep 2014 15:45:23 +0000
+Subject: Bug #4234: Use the Firefox Update Process for Tor Browser.
+
+New configure options:
+ --with-tor-browser-version=VERSION # Pass TB version throughout build.
+ --enable-tor-browser-update # Enable bundle update behavior.
+The following files are never updated:
+ TorBrowser/Data/Browser/profiles.ini
+ TorBrowser/Data/Browser/profile.default/bookmarks.html
+ TorBrowser/Data/Tor/torrc
+Mac OS: Store update metadata under TorBrowser/UpdateInfo.
+Removed the %OS_VERSION% component from the update URL (13047) and
+ added support for minSupportedOSVersion, an attribute of the
+ <update> element that may be used to trigger Firefox's
+ "unsupported platform" behavior.
+Windows: disable "runas" code path in updater (15201).
+Windows: avoid writing to the registry (16236).
+Also includes fixes for tickets 13047, 13301, 13356, 13594, 15406,
+ 16014, and 16909.
+
+diff --git a/browser/components/moz.build b/browser/components/moz.build
+index 431d505..bf7a40c 100644
+--- a/browser/components/moz.build
++++ b/browser/components/moz.build
+@@ -38,11 +38,8 @@ XPIDL_MODULE = 'browsercompsbase'
+
+ EXTRA_PP_COMPONENTS += [
+ 'BrowserComponents.manifest',
+- 'nsBrowserGlue.js',
+-]
+-
+-EXTRA_COMPONENTS += [
+ 'nsBrowserContentHandler.js',
++ 'nsBrowserGlue.js',
+ ]
+
+ EXTRA_JS_MODULES += [
+diff --git a/browser/components/nsBrowserContentHandler.js b/browser/components/nsBrowserContentHandler.js
+index e89004d..b892eaf 100644
+--- a/browser/components/nsBrowserContentHandler.js
++++ b/browser/components/nsBrowserContentHandler.js
+@@ -45,6 +45,10 @@ const NS_BINDING_ABORTED = Components.results.NS_BINDING_ABORTED;
+ const NS_ERROR_WONT_HANDLE_CONTENT = 0x805d0001;
+ const NS_ERROR_ABORT = Components.results.NS_ERROR_ABORT;
+
++#ifdef TOR_BROWSER_VERSION
++const kTBSavedVersionPref = "browser.startup.homepage_override.torbrowser.version";
++#endif
++
+ function shouldLoadURI(aURI) {
+ if (aURI && !aURI.schemeIs("chrome"))
+ return true;
+@@ -96,7 +100,8 @@ const OVERRIDE_NEW_BUILD_ID = 3;
+ * Returns:
+ * OVERRIDE_NEW_PROFILE if this is the first run with a new profile.
+ * OVERRIDE_NEW_MSTONE if this is the first run with a build with a different
+- * Gecko milestone (i.e. right after an upgrade).
++ * Gecko milestone or Tor Browser version (i.e. right
++ * after an upgrade).
+ * OVERRIDE_NEW_BUILD_ID if this is the first run with a new build ID of the
+ * same Gecko milestone (i.e. after a nightly upgrade).
+ * OVERRIDE_NONE otherwise.
+@@ -112,6 +117,15 @@ function needHomepageOverride(prefb) {
+
+ var mstone = Services.appinfo.platformVersion;
+
++#ifdef TOR_BROWSER_VERSION
++#expand const TOR_BROWSER_VERSION = __TOR_BROWSER_VERSION__;
++
++ var savedTBVersion = null;
++ try {
++ savedTBVersion = prefb.getCharPref(kTBSavedVersionPref);
++ } catch (e) {}
++#endif
++
+ var savedBuildID = null;
+ try {
+ savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID");
+@@ -129,9 +143,30 @@ function needHomepageOverride(prefb) {
+
+ prefb.setCharPref("browser.startup.homepage_override.mstone", mstone);
+ prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
++#ifdef TOR_BROWSER_VERSION
++ prefb.setCharPref(kTBSavedVersionPref, TOR_BROWSER_VERSION);
++
++ // After an upgrade from an older release of Tor Browser (<= 5.5a1), the
++ // savedmstone will be undefined because those releases included the
++ // value "ignore" for the browser.startup.homepage_override.mstone pref.
++ // To correctly detect an upgrade vs. a new profile, we check for the
++ // presence of the "app.update.postupdate" pref.
++ var updated = prefb.prefHasUserValue("app.update.postupdate");
++ return (savedmstone || updated) ? OVERRIDE_NEW_MSTONE
++ : OVERRIDE_NEW_PROFILE;
++#else
+ return (savedmstone ? OVERRIDE_NEW_MSTONE : OVERRIDE_NEW_PROFILE);
++#endif
+ }
+
++#ifdef TOR_BROWSER_VERSION
++ if (TOR_BROWSER_VERSION != savedTBVersion) {
++ prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
++ prefb.setCharPref(kTBSavedVersionPref, TOR_BROWSER_VERSION);
++ return OVERRIDE_NEW_MSTONE;
++ }
++#endif
++
+ if (buildID != savedBuildID) {
+ prefb.setCharPref("browser.startup.homepage_override.buildID", buildID);
+ return OVERRIDE_NEW_BUILD_ID;
+@@ -515,6 +550,15 @@ nsBrowserContentHandler.prototype = {
+ try {
+ old_mstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone");
+ } catch (ex) {}
++
++#ifdef TOR_BROWSER_VERSION
++ // We do the same for the Tor Browser version.
++ var old_tbversion = null;
++ try {
++ old_tbversion = prefb.getCharPref(kTBSavedVersionPref);
++ } catch (e) {}
++#endif
++
+ override = needHomepageOverride(prefb);
+ if (override != OVERRIDE_NONE) {
+ switch (override) {
+@@ -538,6 +582,10 @@ nsBrowserContentHandler.prototype = {
+ overridePage = getPostUpdateOverridePage(overridePage);
+
+ overridePage = overridePage.replace("%OLD_VERSION%", old_mstone);
++#ifdef TOR_BROWSER_VERSION
++ overridePage = overridePage.replace("%OLD_TOR_BROWSER_VERSION%",
++ old_tbversion);
++#endif
+ break;
+ }
+ }
+diff --git a/browser/confvars.sh b/browser/confvars.sh
+index 6935e05..ed93deb 100755
+--- a/browser/confvars.sh
++++ b/browser/confvars.sh
+@@ -8,22 +8,6 @@ MOZ_APP_VENDOR=Mozilla
+ MOZ_UPDATER=1
+ MOZ_PHOENIX=1
+
+-if test "$OS_ARCH" = "WINNT"; then
+- MOZ_MAINTENANCE_SERVICE=1
+- if ! test "$HAVE_64BIT_BUILD"; then
+- if test "$MOZ_UPDATE_CHANNEL" = "nightly" -o \
+- "$MOZ_UPDATE_CHANNEL" = "aurora" -o \
+- "$MOZ_UPDATE_CHANNEL" = "beta" -o \
+- "$MOZ_UPDATE_CHANNEL" = "beta-dev" -o \
+- "$MOZ_UPDATE_CHANNEL" = "release" -o \
+- "$MOZ_UPDATE_CHANNEL" = "release-dev"; then
+- if ! test "$MOZ_DEBUG"; then
+- MOZ_STUB_INSTALLER=1
+- fi
+- fi
+- fi
+-fi
+-
+ # Enable building ./signmar and running libmar signature tests
+ MOZ_ENABLE_SIGNMAR=1
+
+@@ -51,9 +35,9 @@ MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+ # This should usually be the same as the value MAR_CHANNEL_ID.
+ # If more than one ID is needed, then you should use a comma separated list
+ # of values.
+-ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-esr
++ACCEPTED_MAR_CHANNEL_IDS=torbrowser-torproject-release
+ # The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
+-MAR_CHANNEL_ID=firefox-mozilla-esr
++MAR_CHANNEL_ID=torbrowser-torproject-release
+ MOZ_PROFILE_MIGRATOR=1
+ MOZ_APP_STATIC_INI=1
+ MOZ_WEBAPP_RUNTIME=1
+diff --git a/browser/installer/Makefile.in b/browser/installer/Makefile.in
+index bb91b4a..ecab9ad 100644
+--- a/browser/installer/Makefile.in
++++ b/browser/installer/Makefile.in
+@@ -72,6 +72,10 @@ endif
+ endif
+ endif
+
++ifdef TOR_BROWSER_UPDATE
++DEFINES += -DTOR_BROWSER_UPDATE
++endif
++
+ ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET)))
+ DEFINES += -DMOZ_SHARED_MOZGLUE=1
+ endif
+diff --git a/config/createprecomplete.py b/config/createprecomplete.py
+index 3241d52..be571be 100644
+--- a/config/createprecomplete.py
++++ b/config/createprecomplete.py
+@@ -5,13 +5,22 @@
+ # update instructions which is used to remove files and directories that are no
+ # longer present in a complete update. The current working directory is used for
+ # the location to enumerate and to create the precomplete file.
++# For symlinks, remove instructions are always generated.
+
+ import sys
+ import os
+
++# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
++# we should remove all lines in this file that contain:
++# TorBrowser/Data
++
+ def get_build_entries(root_path):
+ """ Iterates through the root_path, creating a list for each file and
+ directory. Excludes any file paths ending with channel-prefs.js.
++ To support Tor Browser updates, excludes:
++ TorBrowser/Data/Browser/profiles.ini
++ TorBrowser/Data/Browser/profile.default/bookmarks.html
++ TorBrowser/Data/Tor/torrc
+ """
+ rel_file_path_set = set()
+ rel_dir_path_set = set()
+@@ -22,6 +31,9 @@ def get_build_entries(root_path):
+ rel_path_file = rel_path_file.replace("\\", "/")
+ if not (rel_path_file.endswith("channel-prefs.js") or
+ rel_path_file.endswith("update-settings.ini") or
++ rel_path_file == "TorBrowser/Data/Browser/profiles.ini" or
++ rel_path_file == "TorBrowser/Data/Browser/profile.default/bookmarks.html" or
++ rel_path_file == "TorBrowser/Data/Tor/torrc" or
+ rel_path_file.find("distribution/") != -1):
+ rel_file_path_set.add(rel_path_file)
+
+@@ -30,7 +42,10 @@ def get_build_entries(root_path):
+ rel_path_dir = os.path.join(parent_dir_rel_path, dir_name)
+ rel_path_dir = rel_path_dir.replace("\\", "/")+"/"
+ if rel_path_dir.find("distribution/") == -1:
+- rel_dir_path_set.add(rel_path_dir)
++ if (os.path.islink(rel_path_dir[:-1])):
++ rel_file_path_set.add(rel_path_dir[:-1])
++ else:
++ rel_dir_path_set.add(rel_path_dir)
+
+ rel_file_path_list = list(rel_file_path_set)
+ rel_file_path_list.sort(reverse=True)
+diff --git a/configure.in b/configure.in
+index 38df30e..e9fb038 100644
+--- a/configure.in
++++ b/configure.in
+@@ -3369,15 +3369,12 @@ AC_SUBST(GRE_MILESTONE)
+ # set RELEASE_BUILD and NIGHTLY_BUILD variables depending on the cycle we're in
+ # The logic works like this:
+ # - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
+-# - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
+ # - otherwise, we're building Release/Beta (define RELEASE_BUILD)
+ case "$GRE_MILESTONE" in
+ *a1*)
+ NIGHTLY_BUILD=1
+ AC_DEFINE(NIGHTLY_BUILD)
+ ;;
+- *a*)
+- ;;
+ *)
+ RELEASE_BUILD=1
+ AC_DEFINE(RELEASE_BUILD)
+@@ -6521,6 +6518,31 @@ MOZ_ARG_ENABLE_BOOL(update-packaging,
+ AC_SUBST(MOZ_UPDATE_PACKAGING)
+
+ dnl ========================================================
++dnl Tor Additions
++dnl ========================================================
++MOZ_ARG_WITH_STRING(eor-browser-version,
++[ --with-tor-browser-version=VERSION
++ Set Tor Browser version, e.g., 4.0b1],
++ TOR_BROWSER_VERSION="$withval")
++
++MOZ_ARG_ENABLE_BOOL(tor-browser-update,
++[ --enable-tor-browser-update
++ Enable Tor Browser update],
++ TOR_BROWSER_UPDATE=1,
++ TOR_BROWSER_UPDATE= )
++
++if test -n "$TOR_BROWSER_UPDATE"; then
++ if test -z "$TOR_BROWSER_VERSION"; then
++ AC_MSG_ERROR([--enable-tor-browser-update requires --with-tor-browser-version.])
++ fi
++ AC_DEFINE(TOR_BROWSER_UPDATE)
++fi
++
++AC_DEFINE_UNQUOTED(TOR_BROWSER_VERSION,"$TOR_BROWSER_VERSION")
++AC_SUBST(TOR_BROWSER_VERSION)
++AC_SUBST(TOR_BROWSER_UPDATE)
++
++dnl ========================================================
+ dnl build the tests by default
+ dnl ========================================================
+ MOZ_ARG_DISABLE_BOOL(tests,
+@@ -9068,7 +9090,7 @@ if test "$MOZ_DEBUG"; then
+ A11Y_LOG=1
+ fi
+ case "$MOZ_UPDATE_CHANNEL" in
+-aurora|beta|release|esr)
++aurora|alpha|beta|hardened|release|esr)
+ ;;
+ *)
+ A11Y_LOG=1
+diff --git a/js/src/configure.in b/js/src/configure.in
+index 25b4ae8..7fae8a4 100644
+--- a/js/src/configure.in
++++ b/js/src/configure.in
+@@ -2691,15 +2691,12 @@ AC_SUBST(GRE_MILESTONE)
+ dnl set RELEASE_BUILD and NIGHTLY_BUILD variables depending on the cycle we're in
+ dnl The logic works like this:
+ dnl - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
+-dnl - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
+ dnl - otherwise, we're building Release/Beta (define RELEASE_BUILD)
+ case "$GRE_MILESTONE" in
+ *a1*)
+ NIGHTLY_BUILD=1
+ AC_DEFINE(NIGHTLY_BUILD)
+ ;;
+- *a*)
+- ;;
+ *)
+ RELEASE_BUILD=1
+ AC_DEFINE(RELEASE_BUILD)
+diff --git a/toolkit/modules/UpdateUtils.jsm b/toolkit/modules/UpdateUtils.jsm
+index b943467..4638c8e 100644
+--- a/toolkit/modules/UpdateUtils.jsm
++++ b/toolkit/modules/UpdateUtils.jsm
+@@ -20,6 +20,9 @@ const PREF_APP_B2G_VERSION = "b2g.version";
+ const PREF_APP_UPDATE_CUSTOM = "app.update.custom";
+ const PREF_APP_UPDATE_IMEI_HASH = "app.update.imei_hash";
+
++#ifdef TOR_BROWSER_VERSION
++#expand const TOR_BROWSER_VERSION = __TOR_BROWSER_VERSION__;
++#endif
+
+ this.UpdateUtils = {
+ /**
+@@ -70,7 +73,11 @@ this.UpdateUtils = {
+ */
+ formatUpdateURL(url) {
+ url = url.replace(/%PRODUCT%/g, Services.appinfo.name);
++#ifdef TOR_BROWSER_UPDATE
++ url = url.replace(/%VERSION%/g, TOR_BROWSER_VERSION);
++#else
+ url = url.replace(/%VERSION%/g, Services.appinfo.version);
++#endif
+ url = url.replace(/%BUILD_ID%/g, Services.appinfo.appBuildID);
+ url = url.replace(/%BUILD_TARGET%/g, Services.appinfo.OS + "_" + this.ABI);
+ url = url.replace(/%OS_VERSION%/g, this.OSVersion);
+diff --git a/toolkit/modules/debug.js b/toolkit/modules/debug.js
+index ba59c65..486105e 100644
+--- a/toolkit/modules/debug.js
++++ b/toolkit/modules/debug.js
+@@ -41,6 +41,8 @@ this.NS_ASSERT = function NS_ASSERT(condition, message) {
+ switch (defB.getCharPref("app.update.channel")) {
+ case "nightly":
+ case "aurora":
++ case "alpha":
++ case "hardened":
+ case "beta":
+ case "default":
+ releaseBuild = false;
+diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build
+index 0600b82..81125d1 100644
+--- a/toolkit/modules/moz.build
++++ b/toolkit/modules/moz.build
+@@ -72,7 +72,6 @@ EXTRA_JS_MODULES += [
+ 'Task.jsm',
+ 'Timer.jsm',
+ 'Troubleshoot.jsm',
+- 'UpdateUtils.jsm',
+ 'WebChannel.jsm',
+ 'WindowDraggingUtils.jsm',
+ 'ZipUtils.jsm',
+@@ -87,6 +86,7 @@ if not CONFIG['TOR_BROWSER_VERSION']:
+ EXTRA_PP_JS_MODULES += [
+ 'AppConstants.jsm',
+ 'SessionRecorder.jsm',
++ 'UpdateUtils.jsm',
+ ]
+
+ if 'Android' != CONFIG['OS_TARGET']:
+diff --git a/toolkit/mozapps/extensions/AddonManager.jsm b/toolkit/mozapps/extensions/AddonManager.jsm
+index ab63c3d..a453062 100644
+--- a/toolkit/mozapps/extensions/AddonManager.jsm
++++ b/toolkit/mozapps/extensions/AddonManager.jsm
+@@ -23,7 +23,7 @@ if ("@mozilla.org/xre/app-info;1" in Cc) {
+
+ Cu.import("resource://gre/modules/AppConstants.jsm");
+
+-const MOZ_COMPATIBILITY_NIGHTLY = !['aurora', 'beta', 'release', 'esr'].includes(AppConstants.MOZ_UPDATE_CHANNEL);
++const MOZ_COMPATIBILITY_NIGHTLY = !['aurora', 'alpha', 'beta', 'hardened', 'release', 'esr'].includes(AppConstants.MOZ_UPDATE_CHANNEL);
+
+ const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
+ const PREF_DEFAULT_PROVIDERS_ENABLED = "extensions.defaultProviders.enabled";
+diff --git a/toolkit/mozapps/update/content/updates.js b/toolkit/mozapps/update/content/updates.js
+index 48f8bad..40e76c8 100644
+--- a/toolkit/mozapps/update/content/updates.js
++++ b/toolkit/mozapps/update/content/updates.js
+@@ -3,6 +3,8 @@
+ * 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/. */
+
++#filter substitution
++
+ 'use strict';
+
+ // Firefox's macBrowserOverlay.xul includes scripts that define Cc, Ci, and Cr
+@@ -51,6 +53,11 @@ const CERT_ATTR_CHECK_FAILED_NO_UPDATE = 100;
+ const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101;
+ const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
+
++#ifdef TOR_BROWSER_VERSION
++# Add double-quotes back on (stripped by JarMaker.py).
++#expand const TOR_BROWSER_VERSION = "__TOR_BROWSER_VERSION__";
++#endif
++
+ var gLogEnabled = false;
+ var gUpdatesFoundPageId;
+
+@@ -510,8 +517,13 @@ var gUpdates = {
+ return;
+ }
+
++#ifdef TOR_BROWSER_UPDATE
++ var appVersion = TOR_BROWSER_VERSION;
++#else
++ var appVersion = Services.appinfo.version;
++#endif
+ if (!this.update.appVersion ||
+- Services.vc.compare(this.update.appVersion, Services.appinfo.version) == 0) {
++ Services.vc.compare(this.update.appVersion, appVersion) == 0) {
+ aCallback(false);
+ return;
+ }
+@@ -523,6 +535,11 @@ var gUpdates = {
+
+ var self = this;
+ AddonManager.getAllAddons(function(addons) {
++#ifdef TOR_BROWSER_UPDATE
++ let compatVersion = self.update.platformVersion;
++#else
++ let compatVersion = self.update.appVersion;
++#endif
+ self.addons = [];
+ addons.forEach(function(addon) {
+ // Protect against code that overrides the add-ons manager and doesn't
+@@ -551,7 +568,7 @@ var gUpdates = {
+ !addon.appDisabled && !addon.userDisabled &&
+ addon.scope != AddonManager.SCOPE_APPLICATION &&
+ addon.isCompatible &&
+- !addon.isCompatibleWith(self.update.appVersion,
++ !addon.isCompatibleWith(compatVersion,
+ self.update.platformVersion))
+ self.addons.push(addon);
+ }
+@@ -821,9 +838,14 @@ var gIncompatibleCheckPage = {
+ this._totalCount = gUpdates.addons.length;
+
+ this._pBar.mode = "normal";
++#ifdef TOR_BROWSER_UPDATE
++ let compatVersion = gUpdates.update.platformVersion;
++#else
++ let compatVersion = gUpdates.update.appVersion;
++#endif
+ gUpdates.addons.forEach(function(addon) {
+ addon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED,
+- gUpdates.update.appVersion,
++ compatVersion,
+ gUpdates.update.platformVersion);
+ }, this);
+ },
+@@ -848,8 +870,13 @@ var gIncompatibleCheckPage = {
+ // the add-on will become incompatible.
+ let bs = CoC["@mozilla.org/extensions/blocklist;1"].
+ getService(CoI.nsIBlocklistService);
++#ifdef TOR_BROWSER_UPDATE
++ let compatVersion = gUpdates.update.platformVersion;
++#else
++ let compatVersion = gUpdates.update.appVersion;
++#endif
+ if (bs.isAddonBlocklisted(addon,
+- gUpdates.update.appVersion,
++ compatVersion,
+ gUpdates.update.platformVersion))
+ return;
+
+diff --git a/toolkit/mozapps/update/jar.mn b/toolkit/mozapps/update/jar.mn
+index 9bb5d2d..5347123 100644
+--- a/toolkit/mozapps/update/jar.mn
++++ b/toolkit/mozapps/update/jar.mn
+@@ -7,6 +7,6 @@ toolkit.jar:
+ content/mozapps/update/history.xul (content/history.xul)
+ content/mozapps/update/history.js (content/history.js)
+ content/mozapps/update/updates.css (content/updates.css)
+- content/mozapps/update/updates.js (content/updates.js)
++* content/mozapps/update/updates.js (content/updates.js)
+ content/mozapps/update/updates.xml (content/updates.xml)
+ content/mozapps/update/updates.xul (content/updates.xul)
+diff --git a/toolkit/mozapps/update/moz.build b/toolkit/mozapps/update/moz.build
+index 3824b88..c93100a 100644
+--- a/toolkit/mozapps/update/moz.build
++++ b/toolkit/mozapps/update/moz.build
+@@ -18,11 +18,14 @@ XPIDL_SOURCES += [
+ TEST_DIRS += ['tests']
+
+ EXTRA_COMPONENTS += [
+- 'nsUpdateService.js',
+ 'nsUpdateService.manifest',
+ 'nsUpdateServiceStub.js',
+ ]
+
++EXTRA_PP_COMPONENTS += [
++ 'nsUpdateService.js',
++]
++
+ EXTRA_JS_MODULES += [
+ 'UpdateTelemetry.jsm',
+ ]
+diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js
+index 489d085..e12636d 100644
+--- a/toolkit/mozapps/update/nsUpdateService.js
++++ b/toolkit/mozapps/update/nsUpdateService.js
+@@ -12,7 +12,9 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
+ Cu.import("resource://gre/modules/FileUtils.jsm", this);
+ Cu.import("resource://gre/modules/AddonManager.jsm", this);
+ Cu.import("resource://gre/modules/Services.jsm", this);
++#ifdef XP_WIN
+ Cu.import("resource://gre/modules/ctypes.jsm", this);
++#endif
+ Cu.import("resource://gre/modules/UpdateTelemetry.jsm", this);
+ Cu.import("resource://gre/modules/AppConstants.jsm", this);
+
+@@ -66,6 +68,10 @@ const KEY_EXECUTABLE = "XREExeF";
+ // Gonk only
+ const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD";
+
++#ifdef TOR_BROWSER_VERSION
++#expand const TOR_BROWSER_VERSION = __TOR_BROWSER_VERSION__;
++#endif
++
+ const DIR_UPDATED = "updated";
+ const DIR_UPDATED_APP = "Updated.app";
+ const DIR_UPDATES = "updates";
+@@ -701,8 +707,13 @@ function getUpdatesDirInApplyToDir() {
+ if (AppConstants.platform == "macosx") {
+ dir = dir.parent.parent; // the bundle directory
+ dir.append(DIR_UPDATED_APP);
++#if defined(TOR_BROWSER_UPDATE) && !defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++ dir.append("TorBrowser");
++ dir.append("UpdateInfo");
++#else
+ dir.append("Contents");
+ dir.append("MacOS");
++#endif
+ } else {
+ dir.append(DIR_UPDATED);
+ }
+@@ -1521,7 +1532,17 @@ function Update(update) {
+ this._patches.push(patch);
+ }
+
+- if (this._patches.length == 0 && !update.hasAttribute("unsupported")) {
++ if (update.hasAttribute("unsupported")) {
++ this.unsupported = ("true" == update.getAttribute("unsupported"));
++ } else if (update.hasAttribute("minSupportedOSVersion")) {
++ let minOSVersion = update.getAttribute("minSupportedOSVersion");
++ try {
++ let osVersion = Services.sysinfo.getProperty("version");
++ this.unsupported = (Services.vc.compare(osVersion, minOSVersion) < 0);
++ } catch (e) {}
++ }
++
++ if (this._patches.length == 0 && !this.unsupported) {
+ throw Cr.NS_ERROR_ILLEGAL_VALUE;
+ }
+
+@@ -1574,15 +1595,13 @@ function Update(update) {
+ if(!isNaN(attr.value)) {
+ this.promptWaitTime = parseInt(attr.value);
+ }
+- } else if (attr.name == "unsupported") {
+- this.unsupported = attr.value == "true";
+ } else if (attr.name == "version") {
+ // Prevent version from replacing displayVersion if displayVersion is
+ // present in the update xml.
+ if (!this.displayVersion) {
+ this.displayVersion = attr.value;
+ }
+- } else {
++ } else if (attr.name != "unsupported") {
+ this[attr.name] = attr.value;
+
+ switch (attr.name) {
+@@ -2408,9 +2427,14 @@ UpdateService.prototype = {
+ updates.forEach(function(aUpdate) {
+ // Ignore updates for older versions of the application and updates for
+ // the same version of the application with the same build ID.
+- if (vc.compare(aUpdate.appVersion, Services.appinfo.version) < 0 ||
+- vc.compare(aUpdate.appVersion, Services.appinfo.version) == 0 &&
+- aUpdate.buildID == Services.appinfo.appBuildID) {
++#ifdef TOR_BROWSER_UPDATE
++ var compatVersion = TOR_BROWSER_VERSION;
++#else
++ var compatVersion = Services.appinfo.version;
++#endif
++ var rc = vc.compare(aUpdate.appVersion, compatVersion);
++ if (rc < 0 || ((rc == 0) &&
++ (aUpdate.buildID == Services.appinfo.appBuildID))) {
+ LOG("UpdateService:selectUpdate - skipping update because the " +
+ "update's application version is less than the current " +
+ "application version");
+@@ -2574,8 +2598,13 @@ UpdateService.prototype = {
+ }
+
+ // Only check add-on compatibility when the version changes.
++#ifdef TOR_BROWSER_UPDATE
++ var compatVersion = TOR_BROWSER_VERSION;
++#else
++ var compatVersion = Services.appinfo.version;
++#endif
+ if (update.appVersion &&
+- Services.vc.compare(update.appVersion, Services.appinfo.version) != 0) {
++ Services.vc.compare(update.appVersion, compatVersion) != 0) {
+ this._update = update;
+ this._checkAddonCompatibility();
+ }
+@@ -2606,6 +2635,11 @@ UpdateService.prototype = {
+ // Get all the installed add-ons
+ var self = this;
+ AddonManager.getAllAddons(function(addons) {
++#ifdef TOR_BROWSER_UPDATE
++ let compatVersion = self._update.platformVersion;
++#else
++ let compatVersion = self._update.appVersion;
++#endif
+ self._incompatibleAddons = [];
+ addons.forEach(function(addon) {
+ // Protect against code that overrides the add-ons manager and doesn't
+@@ -2635,7 +2669,7 @@ UpdateService.prototype = {
+ !addon.appDisabled && !addon.userDisabled &&
+ addon.scope != AddonManager.SCOPE_APPLICATION &&
+ addon.isCompatible &&
+- !addon.isCompatibleWith(self._update.appVersion,
++ !addon.isCompatibleWith(compatVersion,
+ self._update.platformVersion)) {
+ self._incompatibleAddons.push(addon);
+ }
+@@ -2671,7 +2705,7 @@ UpdateService.prototype = {
+
+ self._incompatibleAddons.forEach(function(addon) {
+ addon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED,
+- this._update.appVersion, this._update.platformVersion);
++ compatVersion, this._update.platformVersion);
+ }, self);
+ }
+ else {
+@@ -2707,7 +2741,12 @@ UpdateService.prototype = {
+ // If the new version of this add-on is blocklisted for the new application
+ // then it isn't a valid update and the user should still be warned that
+ // the add-on will become incompatible.
+- if (Services.blocklist.isAddonBlocklisted(addon, this._update.appVersion,
++#ifdef TOR_BROWSER_UPDATE
++ let compatVersion = this._update.platformVersion;
++#else
++ let compatVersion = this._update.appVersion;
++#endif
++ if (Services.blocklist.isAddonBlocklisted(addon, compatVersion,
+ this._update.platformVersion)) {
+ return;
+ }
+@@ -2819,14 +2858,24 @@ UpdateService.prototype = {
+ // current application's version or the update's version is the same as the
+ // application's version and the build ID is the same as the application's
+ // build ID.
++#ifdef TOR_BROWSER_UPDATE
++ var compatVersion = TOR_BROWSER_VERSION;
++#else
++ var compatVersion = Services.appinfo.version;
++#endif
+ if (update.appVersion &&
+- (Services.vc.compare(update.appVersion, Services.appinfo.version) < 0 ||
++ (Services.vc.compare(update.appVersion, compatVersion) < 0 ||
+ update.buildID && update.buildID == Services.appinfo.appBuildID &&
+- update.appVersion == Services.appinfo.version)) {
++ update.appVersion == compatVersion)) {
+ LOG("UpdateService:downloadUpdate - canceling download of update since " +
+ "it is for an earlier or same application version and build ID.\n" +
+- "current application version: " + Services.appinfo.version + "\n" +
++#ifdef TOR_BROWSER_UPDATE
++ "current Tor Browser version: " + compatVersion + "\n" +
++ "update Tor Browser version : " + update.appVersion + "\n" +
++#else
++ "current application version: " + compatVersion + "\n" +
+ "update application version : " + update.appVersion + "\n" +
++#endif
+ "current build ID: " + Services.appinfo.appBuildID + "\n" +
+ "update build ID : " + update.buildID);
+ cleanupActiveUpdate();
+@@ -2859,7 +2908,7 @@ UpdateService.prototype = {
+ }
+ }
+ // Set the previous application version prior to downloading the update.
+- update.previousAppVersion = Services.appinfo.version;
++ update.previousAppVersion = compatVersion;
+ this._downloader = new Downloader(background, this);
+ return this._downloader.downloadUpdate(update);
+ },
+diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp
+index 6ef82a1..f362292 100644
+--- a/toolkit/mozapps/update/updater/updater.cpp
++++ b/toolkit/mozapps/update/updater/updater.cpp
+@@ -25,7 +25,7 @@
+ * updatev3.manifest
+ * -----------------
+ * method = "add" | "add-if" | "add-if-not" | "patch" | "patch-if" |
+- * "remove" | "rmdir" | "rmrfdir" | type
++ * "remove" | "rmdir" | "rmrfdir" | "addsymlink" | type
+ *
+ * 'add-if-not' adds a file if it doesn't exist.
+ *
+@@ -403,10 +403,12 @@ get_full_path(const NS_tchar *relpath)
+ * The line from the manifest that contains the path.
+ * @param isdir
+ * Whether the path is a directory path. Defaults to false.
++ * @param islinktarget
++ * Whether the path is a symbolic link target. Defaults to false.
+ * @return valid filesystem path or nullptr if the path checks fail.
+ */
+ static NS_tchar*
+-get_valid_path(NS_tchar **line, bool isdir = false)
++get_valid_path(NS_tchar **line, bool isdir = false, bool islinktarget = false)
+ {
+ NS_tchar *path = mstrtok(kQuote, line);
+ if (!path) {
+@@ -441,10 +443,12 @@ get_valid_path(NS_tchar **line, bool isdir = false)
+ path[NS_tstrlen(path) - 1] = NS_T('\0');
+ }
+
+- // Don't allow relative paths that resolve to a parent directory.
+- if (NS_tstrstr(path, NS_T("..")) != nullptr) {
+- LOG(("get_valid_path: paths must not contain '..': " LOG_S, path));
+- return nullptr;
++ if (!islinktarget) {
++ // Don't allow relative paths that resolve to a parent directory.
++ if (NS_tstrstr(path, NS_T("..")) != nullptr) {
++ LOG(("get_valid_path: paths must not contain '..': " LOG_S, path));
++ return nullptr;
++ }
+ }
+
+ return path;
+@@ -479,7 +483,8 @@ static void ensure_write_permissions(const NS_tchar *path)
+ (void) _wchmod(path, _S_IREAD | _S_IWRITE);
+ #else
+ struct stat fs;
+- if (!stat(path, &fs) && !(fs.st_mode & S_IWUSR)) {
++ if (!lstat(path, &fs) && !S_ISLNK(fs.st_mode)
++ && !(fs.st_mode & S_IWUSR)) {
+ (void)chmod(path, fs.st_mode | S_IWUSR);
+ }
+ #endif
+@@ -680,11 +685,9 @@ static int ensure_copy(const NS_tchar *path, const NS_tchar *dest)
+ return READ_ERROR;
+ }
+
+-#ifdef XP_UNIX
+ if (S_ISLNK(ss.st_mode)) {
+ return ensure_copy_symlink(path, dest);
+ }
+-#endif
+
+ #if MAYBE_USE_HARD_LINKS
+ if (sUseHardLinks) {
+@@ -780,7 +783,7 @@ static int ensure_copy_recursive(const NS_tchar *path, const NS_tchar *dest,
+ return READ_ERROR;
+ }
+
+-#ifdef XP_UNIX
++#ifndef XP_WIN
+ if (S_ISLNK(sInfo.st_mode)) {
+ return ensure_copy_symlink(path, dest);
+ }
+@@ -839,14 +842,19 @@ static int rename_file(const NS_tchar *spath, const NS_tchar *dpath,
+ return rv;
+
+ struct NS_tstat_t spathInfo;
+- rv = NS_tstat(spath, &spathInfo);
++ rv = NS_tlstat(spath, &spathInfo); // Get info about file or symlink.
+ if (rv) {
+ LOG(("rename_file: failed to read file status info: " LOG_S ", " \
+ "err: %d", spath, errno));
+ return READ_ERROR;
+ }
+
+- if (!S_ISREG(spathInfo.st_mode)) {
++#ifdef XP_WIN
++ if (!S_ISREG(spathInfo.st_mode))
++#else
++ if (!S_ISREG(spathInfo.st_mode) && !S_ISLNK(spathInfo.st_mode))
++#endif
++ {
+ if (allowDirs && !S_ISDIR(spathInfo.st_mode)) {
+ LOG(("rename_file: path present, but not a file: " LOG_S ", err: %d",
+ spath, errno));
+@@ -856,7 +864,12 @@ static int rename_file(const NS_tchar *spath, const NS_tchar *dpath,
+ }
+ }
+
+- if (!NS_taccess(dpath, F_OK)) {
++#ifdef XP_WIN
++ if (!NS_taccess(dpath, F_OK))
++#else
++ if (!S_ISLNK(spathInfo.st_mode) && !NS_taccess(dpath, F_OK))
++#endif
++ {
+ if (ensure_remove(dpath)) {
+ LOG(("rename_file: destination file exists and could not be " \
+ "removed: " LOG_S, dpath));
+@@ -873,7 +886,7 @@ static int rename_file(const NS_tchar *spath, const NS_tchar *dpath,
+ return OK;
+ }
+
+-#ifdef XP_WIN
++#if defined(XP_WIN) && !defined(TOR_BROWSER_UPDATE)
+ // Remove the directory pointed to by path and all of its files and
+ // sub-directories. If a file is in use move it to the tobedeleted directory
+ // and attempt to schedule removal of the file on reboot
+@@ -960,7 +973,18 @@ static int backup_restore(const NS_tchar *path)
+ NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
+ NS_T("%s") BACKUP_EXT, path);
+
+- if (NS_taccess(backup, F_OK)) {
++ bool isLink = false;
++#ifndef XP_WIN
++ struct stat linkInfo;
++ int rv = lstat(path, &linkInfo);
++ if (!rv) {
++ LOG(("backup_restore: cannot get info for backup file: " LOG_S, backup));
++ return OK;
++ }
++ isLink = S_ISLNK(linkInfo.st_mode);
++#endif
++
++ if (!isLink && NS_taccess(backup, F_OK)) {
+ LOG(("backup_restore: backup file doesn't exist: " LOG_S, backup));
+ return OK;
+ }
+@@ -975,8 +999,18 @@ static int backup_discard(const NS_tchar *path)
+ NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
+ NS_T("%s") BACKUP_EXT, path);
+
++ bool isLink = false;
++#ifndef XP_WIN
++ struct stat linkInfo;
++ int rv2 = lstat(backup, &linkInfo);
++ if (rv2) {
++ return OK; // File does not exist; nothing to do.
++ }
++ isLink = S_ISLNK(linkInfo.st_mode);
++#endif
++
+ // Nothing to discard
+- if (NS_taccess(backup, F_OK)) {
++ if (!isLink && NS_taccess(backup, F_OK)) {
+ return OK;
+ }
+
+@@ -991,6 +1025,8 @@ static int backup_discard(const NS_tchar *path)
+ backup, path));
+ return WRITE_ERROR_DELETE_BACKUP;
+ }
++
++#if !defined(TOR_BROWSER_UPDATE)
+ // The MoveFileEx call to remove the file on OS reboot will fail if the
+ // process doesn't have write access to the HKEY_LOCAL_MACHINE registry key
+ // but this is ok since the installer / uninstaller will delete the
+@@ -1003,6 +1039,7 @@ static int backup_discard(const NS_tchar *path)
+ LOG(("backup_discard: failed to schedule OS reboot removal of " \
+ "file: " LOG_S, path));
+ }
++#endif
+ }
+ #else
+ if (rv)
+@@ -1056,7 +1093,7 @@ private:
+ class RemoveFile : public Action
+ {
+ public:
+- RemoveFile() : mFile(nullptr), mSkip(0) { }
++ RemoveFile() : mFile(nullptr), mSkip(0), mIsLink(0) { }
+
+ int Parse(NS_tchar *line);
+ int Prepare();
+@@ -1066,6 +1103,7 @@ public:
+ private:
+ const NS_tchar *mFile;
+ int mSkip;
++ int mIsLink;
+ };
+
+ int
+@@ -1083,28 +1121,39 @@ RemoveFile::Parse(NS_tchar *line)
+ int
+ RemoveFile::Prepare()
+ {
+- // Skip the file if it already doesn't exist.
+- int rv = NS_taccess(mFile, F_OK);
+- if (rv) {
+- mSkip = 1;
+- mProgressCost = 0;
+- return OK;
++ int rv;
++#ifndef XP_WIN
++ struct stat linkInfo;
++ rv = lstat(mFile, &linkInfo);
++ mIsLink = ((0 == rv) && S_ISLNK(linkInfo.st_mode));
++#endif
++
++ if (!mIsLink) {
++ // Skip the file if it already doesn't exist.
++ rv = NS_taccess(mFile, F_OK);
++ if (rv) {
++ mSkip = 1;
++ mProgressCost = 0;
++ return OK;
++ }
+ }
+
+ LOG(("PREPARE REMOVEFILE " LOG_S, mFile));
+
+- // Make sure that we're actually a file...
+- struct NS_tstat_t fileInfo;
+- rv = NS_tstat(mFile, &fileInfo);
+- if (rv) {
+- LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
+- errno));
+- return READ_ERROR;
+- }
++ if (!mIsLink) {
++ // Make sure that we're actually a file...
++ struct NS_tstat_t fileInfo;
++ rv = NS_tstat(mFile, &fileInfo);
++ if (rv) {
++ LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
++ errno));
++ return READ_ERROR;
++ }
+
+- if (!S_ISREG(fileInfo.st_mode)) {
+- LOG(("path present, but not a file: " LOG_S, mFile));
+- return DELETE_ERROR_EXPECTED_FILE;
++ if (!S_ISREG(fileInfo.st_mode)) {
++ LOG(("path present, but not a file: " LOG_S, mFile));
++ return DELETE_ERROR_EXPECTED_FILE;
++ }
+ }
+
+ NS_tchar *slash = (NS_tchar *) NS_tstrrchr(mFile, NS_T('/'));
+@@ -1134,7 +1183,13 @@ RemoveFile::Execute()
+
+ // The file is checked for existence here and in Prepare since it might have
+ // been removed by a separate instruction: bug 311099.
+- int rv = NS_taccess(mFile, F_OK);
++ int rv = 0;
++ if (mIsLink) {
++ struct NS_tstat_t linkInfo;
++ rv = NS_tlstat(mFile, &linkInfo);
++ } else {
++ rv = NS_taccess(mFile, F_OK);
++ }
+ if (rv) {
+ LOG(("file cannot be removed because it does not exist; skipping"));
+ mSkip = 1;
+@@ -1814,6 +1869,97 @@ PatchIfFile::Finish(int status)
+ PatchFile::Finish(status);
+ }
+
++#ifndef XP_WIN
++class AddSymlink : public Action
++{
++public:
++ AddSymlink() : mLinkName(NULL)
++ , mTarget(NULL)
++ , mAdded(false)
++ { }
++
++ virtual int Parse(NS_tchar *line);
++ virtual int Prepare();
++ virtual int Execute();
++ virtual void Finish(int status);
++
++private:
++ const NS_tchar *mLinkName;
++ const NS_tchar *mTarget;
++ bool mAdded;
++};
++
++int
++AddSymlink::Parse(NS_tchar *line)
++{
++ // format "<linkname>" "target"
++
++ mLinkName = get_valid_path(&line);
++ if (!mLinkName)
++ return PARSE_ERROR;
++
++ // consume whitespace between args
++ NS_tchar *q = mstrtok(kQuote, &line);
++ if (!q)
++ return PARSE_ERROR;
++
++ mTarget = get_valid_path(&line, false, true);
++ if (!mTarget)
++ return PARSE_ERROR;
++
++ return OK;
++}
++
++int
++AddSymlink::Prepare()
++{
++ LOG(("PREPARE ADDSYMLINK " LOG_S " -> " LOG_S, mLinkName, mTarget));
++
++ return OK;
++}
++
++int
++AddSymlink::Execute()
++{
++ LOG(("EXECUTE ADDSYMLINK " LOG_S " -> " LOG_S, mLinkName, mTarget));
++
++ // First make sure that we can actually get rid of any existing file or link.
++ struct stat linkInfo;
++ int rv = lstat(mLinkName, &linkInfo);
++ if ((0 == rv) && !S_ISLNK(linkInfo.st_mode)) {
++ rv = NS_taccess(mLinkName, F_OK);
++ }
++ if (rv == 0) {
++ rv = backup_create(mLinkName);
++ if (rv)
++ return rv;
++ } else {
++ rv = ensure_parent_dir(mLinkName);
++ if (rv)
++ return rv;
++ }
++
++ // Create the link.
++ rv = symlink(mTarget, mLinkName);
++ if (!rv) {
++ mAdded = true;
++ }
++
++ return rv;
++}
++
++void
++AddSymlink::Finish(int status)
++{
++ LOG(("FINISH ADDSYMLINK " LOG_S " -> " LOG_S, mLinkName, mTarget));
++ // When there is an update failure and a link has been added it is removed
++ // here since there might not be a backup to replace it.
++ if (status && mAdded)
++ NS_tremove(mLinkName);
++ backup_finish(mLinkName, status);
++}
++#endif
++
+ //-----------------------------------------------------------------------------
+
+ #ifdef XP_WIN
+@@ -2115,14 +2261,29 @@ static int
+ CopyInstallDirToDestDir()
+ {
+ // These files should not be copied over to the updated app
+-#ifdef XP_WIN
+-#define SKIPLIST_COUNT 3
+-#elif XP_MACOSX
+-#define SKIPLIST_COUNT 0
++#if defined(TOR_BROWSER_UPDATE) && !defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++ #ifdef XP_WIN
++ #define SKIPLIST_COUNT 6
++ #else
++ #define SKIPLIST_COUNT 5
++ #endif
+ #else
+-#define SKIPLIST_COUNT 2
++ #ifdef XP_WIN
++ #define SKIPLIST_COUNT 3
++ #elif XP_MACOSX
++ #define SKIPLIST_COUNT 0
++ #else
++ #define SKIPLIST_COUNT 2
++ #endif
+ #endif
+ copy_recursive_skiplist<SKIPLIST_COUNT> skiplist;
++#if defined(TOR_BROWSER_UPDATE) && !defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++#ifdef XP_MACOSX
++ skiplist.append(0, gInstallDirPath, NS_T("Updated.app"));
++ skiplist.append(1, gInstallDirPath, NS_T("TorBrowser/UpdateInfo/updates/0"));
++#endif
++#endif
++
+ #ifndef XP_MACOSX
+ skiplist.append(0, gInstallDirPath, NS_T("updated"));
+ skiplist.append(1, gInstallDirPath, NS_T("updates/0"));
+@@ -2131,6 +2292,23 @@ CopyInstallDirToDestDir()
+ #endif
+ #endif
+
++#if defined(TOR_BROWSER_UPDATE) && !defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++#ifdef XP_WIN
++ skiplist.append(SKIPLIST_COUNT - 3, gInstallDirPath,
++ NS_T("TorBrowser/Data/Browser/profile.default/parent.lock"));
++ skiplist.append(SKIPLIST_COUNT - 2, gInstallDirPath,
++ NS_T("TorBrowser/Data/Browser/profile.meek-http-helper/parent.lock"));
++#else
++ skiplist.append(SKIPLIST_COUNT - 3, gInstallDirPath,
++ NS_T("TorBrowser/Data/Browser/profile.default/.parentlock"));
++ skiplist.append(SKIPLIST_COUNT - 2, gInstallDirPath,
++ NS_T("TorBrowser/Data/Browser/profile.meek-http-helper/.parentlock"));
++#endif
++
++skiplist.append(SKIPLIST_COUNT - 1, gInstallDirPath,
++ NS_T("TorBrowser/Data/Tor/lock"));
++#endif
++
+ return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist);
+ }
+
+@@ -2251,16 +2429,52 @@ ProcessReplaceRequest()
+ if (NS_taccess(deleteDir, F_OK)) {
+ NS_tmkdir(deleteDir, 0755);
+ }
++#if !defined(TOR_BROWSER_UPDATE)
+ remove_recursive_on_reboot(tmpDir, deleteDir);
+ #endif
++#endif
+ }
+
+ #ifdef XP_MACOSX
+ // On OS X, we we need to remove the staging directory after its Contents
+ // directory has been moved.
+ NS_tchar updatedAppDir[MAXPATHLEN];
++#if defined(TOR_BROWSER_UPDATE) && !defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++ NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]),
++ NS_T("%s/Updated.app"), gInstallDirPath);
++ // For Tor Browser on OS X, we also need to copy everything else that is inside Updated.app.
++ NS_tDIR *dir = NS_topendir(updatedAppDir);
++ if (dir) {
++ NS_tdirent *entry;
++ while ((entry = NS_treaddir(dir)) != 0) {
++ if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
++ NS_tstrcmp(entry->d_name, NS_T(".."))) {
++ NS_tchar childSrcPath[MAXPATHLEN];
++ NS_tsnprintf(childSrcPath, sizeof(childSrcPath)/sizeof(childSrcPath[0]),
++ NS_T("%s/%s"), updatedAppDir, entry->d_name);
++ NS_tchar childDstPath[MAXPATHLEN];
++ NS_tsnprintf(childDstPath, sizeof(childDstPath)/sizeof(childDstPath[0]),
++ NS_T("%s/%s"), gInstallDirPath, entry->d_name);
++ ensure_remove_recursive(childDstPath);
++ rv = rename_file(childSrcPath, childDstPath, true);
++ if (rv) {
++ LOG(("Moving " LOG_S " to " LOG_S " failed, err: %d",
++ childSrcPath, childDstPath, errno));
++ }
++ }
++ }
++
++ NS_tclosedir(dir);
++ } else {
++ LOG(("Updated.app dir can't be found: " LOG_S ", err: %d",
++ updatedAppDir, errno));
++ }
++#else
+ NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]),
+ NS_T("%s/Updated.app"), gPatchDirPath);
++#endif
++
++ // Remove the Updated.app directory.
+ ensure_remove_recursive(updatedAppDir);
+ #endif
+
+@@ -2998,6 +3212,26 @@ int NS_main(int argc, NS_tchar **argv)
+ // using the service is because we are testing.
+ if (!useService && !noServiceFallback &&
+ updateLockFileHandle == INVALID_HANDLE_VALUE) {
++#ifdef TOR_BROWSER_UPDATE
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ // Because the TorBrowser-Data directory that contains the user's
++ // profile is a sibling of the Tor Browser installation directory,
++ // the user probably has permission to apply updates. Therefore, to
++ // avoid potential security issues such as CVE-2015-0833, do not
++ // attempt to elevate privileges. Instead, write a "failed" message
++ // to the update status file (this function will return immediately
++ // after the CloseHandle(elevatedFileHandle) call below).
++#else
++ // Because the user profile is contained within the Tor Browser
++ // installation directory, the user almost certainly has permission to
++ // apply updates. Therefore, to avoid potential security issues such
++ // as CVE-2015-0833, do not attempt to elevate privileges. Instead,
++ // write a "failed" message to the update status file (this function
++ // will return immediately after the CloseHandle(elevatedFileHandle)
++ // call below).
++#endif
++ WriteStatusFile(WRITE_ERROR_ACCESS_DENIED);
++#else
+ SHELLEXECUTEINFO sinfo;
+ memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
+ sinfo.cbSize = sizeof(SHELLEXECUTEINFO);
+@@ -3019,6 +3253,7 @@ int NS_main(int argc, NS_tchar **argv)
+ } else {
+ WriteStatusFile(ELEVATION_CANCELED);
+ }
++#endif
+ }
+
+ if (argc > callbackIndex) {
+@@ -3310,6 +3545,7 @@ int NS_main(int argc, NS_tchar **argv)
+ if (!sStagedUpdate && !sReplaceRequest && _wrmdir(DELETE_DIR)) {
+ LOG(("NS_main: unable to remove directory: " LOG_S ", err: %d",
+ DELETE_DIR, errno));
++#if !defined(TOR_BROWSER_UPDATE)
+ // The directory probably couldn't be removed due to it containing files
+ // that are in use and will be removed on OS reboot. The call to remove the
+ // directory on OS reboot is done after the calls to remove the files so the
+@@ -3326,6 +3562,7 @@ int NS_main(int argc, NS_tchar **argv)
+ LOG(("NS_main: failed to schedule OS reboot removal of " \
+ "directory: " LOG_S, DELETE_DIR));
+ }
++#endif
+ }
+ #endif /* XP_WIN */
+
+@@ -3376,7 +3613,7 @@ int NS_main(int argc, NS_tchar **argv)
+ LogFinish();
+
+ if (argc > callbackIndex) {
+-#if defined(XP_WIN)
++#if defined(XP_WIN) && !defined(TOR_BROWSER_UPDATE)
+ if (gSucceeded) {
+ if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath)) {
+ fprintf(stderr, "The post update process was not launched");
+@@ -4005,6 +4242,11 @@ int DoUpdate()
+ else if (NS_tstrcmp(token, NS_T("patch-if")) == 0) { // Patch if exists
+ action = new PatchIfFile();
+ }
++#ifndef XP_WIN
++ else if (NS_tstrcmp(token, NS_T("addsymlink")) == 0) {
++ action = new AddSymlink();
++ }
++#endif
+ else {
+ LOG(("DoUpdate: unknown token: " LOG_S, token));
+ return PARSE_ERROR;
+diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
+index 6d04d46..a3a2857 100644
+--- a/toolkit/xre/nsAppRunner.cpp
++++ b/toolkit/xre/nsAppRunner.cpp
+@@ -4051,12 +4051,20 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
+ NS_ENSURE_SUCCESS(rv, 1);
+ rv = exeFile->GetParent(getter_AddRefs(exeDir));
+ NS_ENSURE_SUCCESS(rv, 1);
++#ifdef TOR_BROWSER_UPDATE
++ nsAutoCString compatVersion(TOR_BROWSER_VERSION);
++#endif
+ ProcessUpdates(mDirProvider.GetGREDir(),
+ exeDir,
+ updRoot,
+ gRestartArgc,
+ gRestartArgv,
+- mAppData->version);
++#ifdef TOR_BROWSER_UPDATE
++ compatVersion.get()
++#else
++ mAppData->version
++#endif
++ );
+ if (EnvHasValue("MOZ_TEST_PROCESS_UPDATES")) {
+ SaveToEnv("MOZ_TEST_PROCESS_UPDATES=");
+ *aExitFlag = true;
+diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp
+index 83002ca..ee60aee 100644
+--- a/toolkit/xre/nsUpdateDriver.cpp
++++ b/toolkit/xre/nsUpdateDriver.cpp
+@@ -39,6 +39,7 @@
+ # include <windows.h>
+ # include <shlwapi.h>
+ # include "nsWindowsHelpers.h"
++# include "prprf.h"
+ # define getcwd(path, size) _getcwd(path, size)
+ # define getpid() GetCurrentProcessId()
+ #elif defined(XP_UNIX)
+@@ -168,6 +169,46 @@ GetInstallDirPath(nsIFile *appDir, nsACString& installDirPath)
+ return NS_OK;
+ }
+
++#if defined(TOR_BROWSER_UPDATE) && defined(XP_WIN)
++#define PATH_SEPARATOR ";"
++
++// In Tor Browser, updater.exe depends on some DLLs that are located in the
++// app directory. To allow the updater to run when it has been copied into
++// the update directory, we append the app directory to the PATH.
++static nsresult
++AdjustPathForUpdater(nsIFile *appDir)
++{
++ nsAutoCString appPath;
++ nsresult rv = appDir->GetNativePath(appPath);
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ char *s = nullptr;
++ char *pathValue = PR_GetEnv("PATH");
++ if ((nullptr == pathValue) || ('\0' == *pathValue)) {
++ s = PR_smprintf("PATH=%s", appPath.get());
++ } else {
++ s = PR_smprintf("PATH=%s" PATH_SEPARATOR "%s", pathValue, appPath.get());
++ }
++
++ // We intentionally leak the value that is passed into PR_SetEnv() because
++ // the environment will hold a pointer to it.
++ if ((nullptr == s) || (PR_SUCCESS != PR_SetEnv(s)))
++ return NS_ERROR_FAILURE;
++
++ return NS_OK;
++}
++#endif
++
++#ifdef DEBUG
++static void
++dump_argv(const char *aPrefix, char **argv, int argc)
++{
++ printf("%s - %d args\n", aPrefix, argc);
++ for (int i = 0; i < argc; ++i)
++ printf(" %d: %s\n", i, argv[i]);
++}
++#endif
++
+ #if defined(XP_MACOSX)
+ // This is a copy of OS X's XRE_GetBinaryPath from nsAppRunner.cpp with the
+ // gBinaryPath check removed so that the updater can reload the stub executable
+@@ -255,6 +296,33 @@ typedef enum {
+ eAppliedService
+ } UpdateStatus;
+
++#ifdef DEBUG
++static const char *
++UpdateStatusToString(UpdateStatus aStatus)
++{
++ const char *rv = "unknown";
++ switch (aStatus) {
++ case eNoUpdateAction:
++ rv = "NoUpdateAction";
++ break;
++ case ePendingUpdate:
++ rv = "PendingUpdate";
++ break;
++ case ePendingService:
++ rv = "PendingService";
++ break;
++ case eAppliedUpdate:
++ rv = "AppliedUpdate";
++ break;
++ case eAppliedService:
++ rv = "AppliedService";
++ break;
++ }
++
++ return rv;
++}
++#endif
++
+ /**
+ * Returns a value indicating what needs to be done in order to handle an update.
+ *
+@@ -323,12 +391,44 @@ IsOlderVersion(nsIFile *versionFile, const char *appVersion)
+ if (strncmp(buf, kNull, sizeof(kNull) - 1) == 0)
+ return false;
+
++#ifdef DEBUG
++ printf("IsOlderVersion checking appVersion %s against updateVersion %s\n",
++ appVersion, buf);
++#endif
++
+ if (mozilla::Version(appVersion) > buf)
+ return true;
+
+ return false;
+ }
+
++#ifndef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++#if defined(TOR_BROWSER_UPDATE) && defined(XP_MACOSX)
++static nsresult
++GetUpdateDirFromAppDir(nsIFile *aAppDir, nsIFile* *aResult)
++{
++ // On Mac OSX, we stage the update to an Updated.app directory that is
++ // directly below the main Tor Browser.app directory (two levels up from
++ // the appDir).
++ NS_ENSURE_ARG_POINTER(aAppDir);
++ NS_ENSURE_ARG_POINTER(aResult);
++ nsCOMPtr<nsIFile> parentDir1, parentDir2;
++ nsresult rv = aAppDir->GetParent(getter_AddRefs(parentDir1));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ nsCOMPtr<nsIFile> updatedDir;
++ if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) {
++ return NS_ERROR_FAILURE;
++ }
++
++ updatedDir.forget(aResult);
++ return NS_OK;
++}
++#endif
++#endif
++
+ static bool
+ CopyFileIntoUpdateDir(nsIFile *parentDir, const nsACString& leaf, nsIFile *updateDir)
+ {
+@@ -541,7 +641,12 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir,
+ nsAutoCString applyToDir;
+ nsCOMPtr<nsIFile> updatedDir;
+ #ifdef XP_MACOSX
++#if defined(TOR_BROWSER_UPDATE) && !defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++ rv = GetUpdateDirFromAppDir(appDir, getter_AddRefs(updatedDir));
++ if (NS_FAILED(rv)) {
++#else
+ if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) {
++#endif
+ #else
+ if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
+ #endif
+@@ -632,6 +737,13 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir,
+ AppendToLibPath(installDirPath.get());
+ #endif
+
++#if defined(TOR_BROWSER_UPDATE) && defined(XP_WIN)
++ nsresult rv2 = AdjustPathForUpdater(appDir);
++ if (NS_FAILED(rv2)) {
++ LOG(("SwitchToUpdatedApp -- AdjustPathForUpdater failed (0x%x)\n", rv2));
++ }
++#endif
++
+ LOG(("spawning updater process for replacing [%s]\n", updaterPath.get()));
+
+ #if defined(USE_EXECV)
+@@ -807,7 +919,12 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
+ applyToDir.Assign(installDirPath);
+ } else {
+ #ifdef XP_MACOSX
++#if defined(TOR_BROWSER_UPDATE) && !defined(TOR_BROWSER_DATA_OUTSIDE_APP_DIR)
++ rv = GetUpdateDirFromAppDir(appDir, getter_AddRefs(updatedDir));
++ if (NS_FAILED(rv)) {
++#else
+ if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) {
++#endif
+ #else
+ if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
+ #endif
+@@ -911,6 +1028,14 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
+ if (isOSUpdate) {
+ PR_SetEnv("MOZ_OS_UPDATE=1");
+ }
++
++#if defined(TOR_BROWSER_UPDATE) && defined(XP_WIN)
++ nsresult rv2 = AdjustPathForUpdater(appDir);
++ if (NS_FAILED(rv2)) {
++ LOG(("ApplyUpdate -- AdjustPathForUpdater failed (0x%x)\n", rv2));
++ }
++#endif
++
+ #if defined(MOZ_WIDGET_GONK)
+ // We want the updater to be CPU friendly and not subject to being killed by
+ // the low memory killer, so we pass in some preferences to allow it to
+@@ -933,6 +1058,9 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
+ #endif
+
+ LOG(("spawning updater process [%s]\n", updaterPath.get()));
++#ifdef DEBUG
++ dump_argv("ApplyUpdate updater", argv, argc);
++#endif
+
+ #if defined(USE_EXECV)
+ // Don't use execv when staging updates.
+@@ -956,6 +1084,9 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
+ // LaunchChildMac uses posix_spawnp and prefers the current
+ // architecture when launching. It doesn't require a
+ // null-terminated string but it doesn't matter if we pass one.
++#ifdef DEBUG
++ dump_argv("ApplyUpdate after SetupMacCommandLine", argv, argc);
++#endif
+ LaunchChildMac(argc, argv, 0, outpid);
+ if (restart) {
+ exit(0);
+@@ -994,9 +1125,29 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
+ bool restart, bool isOSUpdate, nsIFile *osApplyToDir,
+ ProcessType *pid)
+ {
++#if defined(XP_WIN) && defined(TOR_BROWSER_UPDATE)
++ // Try to remove the "tobedeleted" directory which, if present, contains
++ // files that could not be removed during a previous update (e.g., DLLs
++ // that were in use and therefore locked by Windows).
++ nsCOMPtr<nsIFile> deleteDir;
++ nsresult winrv = appDir->Clone(getter_AddRefs(deleteDir));
++ if (NS_SUCCEEDED(winrv)) {
++ winrv = deleteDir->AppendNative(NS_LITERAL_CSTRING("tobedeleted"));
++ if (NS_SUCCEEDED(winrv)) {
++ winrv = deleteDir->Remove(true);
++ }
++ }
++#endif
++
+ nsresult rv;
+
+ nsCOMPtr<nsIFile> updatesDir;
++#ifdef DEBUG
++ nsAutoCString path;
++ updRootDir->GetNativePath(path);
++ printf("ProcessUpdates updateRootDir: %s appVersion: %s\n",
++ path.get(), appVersion);
++#endif
+ rv = updRootDir->Clone(getter_AddRefs(updatesDir));
+ if (NS_FAILED(rv))
+ return rv;
+@@ -1022,6 +1173,12 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
+
+ nsCOMPtr<nsIFile> statusFile;
+ UpdateStatus status = GetUpdateStatus(updatesDir, statusFile);
++#ifdef DEBUG
++ printf("ProcessUpdates status: %s (%d)\n",
++ UpdateStatusToString(status), status);
++ updatesDir->GetNativePath(path);
++ printf("ProcessUpdates updatesDir: %s\n", path.get());
++#endif
+ switch (status) {
+ case ePendingUpdate:
+ case ePendingService: {
+@@ -1104,7 +1261,11 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
+ if (NS_FAILED(rv))
+ appDir = dirProvider->GetAppDir();
+
++#ifdef TOR_BROWSER_UPDATE
++ appVersion = TOR_BROWSER_VERSION;
++#else
+ appVersion = gAppData->version;
++#endif
+ argc = gRestartArgc;
+ argv = gRestartArgv;
+ } else {
+@@ -1134,6 +1295,8 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
+ getter_AddRefs(updRoot));
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the UpdRootD dir");
+
++ // To support Tor Browser updates from xpcshell, modify the following
++ // code to use TOR_BROWSER_VERSION from the configure process.
+ nsCOMPtr<nsIXULAppInfo> appInfo =
+ do_GetService("@mozilla.org/xre/app-info;1");
+ if (appInfo) {
+diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
+index 831a373..403e820 100644
+--- a/toolkit/xre/nsXREDirProvider.cpp
++++ b/toolkit/xre/nsXREDirProvider.cpp
+@@ -1066,6 +1066,31 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ #ifdef XP_MACOSX
++#ifdef TOR_BROWSER_UPDATE
++#ifdef TOR_BROWSER_DATA_OUTSIDE_APP_DIR
++ // For Tor Browser, we cannot store update history, etc. under the user's
++ // home directory. Instead, we place it under
++ // Tor Browser.app/../TorBrowser-Data/UpdateInfo/
++ nsCOMPtr<nsIFile> appRootDir;
++ rv = GetAppRootDir(getter_AddRefs(appRootDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ nsCOMPtr<nsIFile> localDir;
++ rv = appRootDir->GetParent(getter_AddRefs(localDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser-Data"
++ XPCOM_FILE_PATH_SEPARATOR "UpdateInfo"));
++#else
++ // For Tor Browser, we cannot store update history, etc. under the user's home directory.
++ // Instead, we place it under Tor Browser.app/TorBrowser/UpdateInfo/
++ nsCOMPtr<nsIFile> localDir;
++ rv = GetAppRootDir(getter_AddRefs(localDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = localDir->AppendNative(NS_LITERAL_CSTRING("TorBrowser"));
++ NS_ENSURE_SUCCESS(rv, rv);
++ rv = localDir->AppendNative(NS_LITERAL_CSTRING("UpdateInfo"));
++#endif
++ NS_ENSURE_SUCCESS(rv, rv);
++#else
+ nsCOMPtr<nsIFile> appRootDirFile;
+ nsCOMPtr<nsIFile> localDir;
+ nsAutoString appDirPath;
+@@ -1096,6 +1121,7 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
+ NS_FAILED(localDir->AppendRelativePath(appDirPath))) {
+ return NS_ERROR_FAILURE;
+ }
++#endif
+
+ localDir.forget(aResult);
+ return NS_OK;
+@@ -1243,33 +1269,8 @@ nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal)
+ NS_ENSURE_ARG_POINTER(aFile);
+ nsCOMPtr<nsIFile> localDir;
+
+- nsresult rv = GetAppDir()->Clone(getter_AddRefs(localDir));
++ nsresult rv = GetAppRootDir(getter_AddRefs(localDir));
+ NS_ENSURE_SUCCESS(rv, rv);
+-
+- int levelsToRemove = 0; // In FF21+, appDir points to browser subdirectory.
+-#if defined(XP_MACOSX)
+- levelsToRemove += 1;
+-#endif
+- while (localDir && (levelsToRemove > 0)) {
+- // When crawling up the hierarchy, components named "." do not count.
+- nsAutoCString removedName;
+- rv = localDir->GetNativeLeafName(removedName);
+- NS_ENSURE_SUCCESS(rv, rv);
+- bool didRemove = !removedName.Equals(".");
+-
+- // Remove a directory component.
+- nsCOMPtr<nsIFile> parentDir;
+- rv = localDir->GetParent(getter_AddRefs(parentDir));
+- NS_ENSURE_SUCCESS(rv, rv);
+- localDir = parentDir;
+-
+- if (didRemove)
+- --levelsToRemove;
+- }
+-
+- if (!localDir)
+- return NS_ERROR_FAILURE;
+-
+ rv = localDir->AppendRelativeNativePath(NS_LITERAL_CSTRING("TorBrowser"
+ XPCOM_FILE_PATH_SEPARATOR "Data"
+ XPCOM_FILE_PATH_SEPARATOR "Browser"));
+@@ -1376,6 +1377,44 @@ nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal,
+ }
+
+ nsresult
++nsXREDirProvider::GetAppRootDir(nsIFile* *aFile)
++{
++ NS_ENSURE_ARG_POINTER(aFile);
++ nsCOMPtr<nsIFile> appRootDir;
++
++ nsresult rv = GetAppDir()->Clone(getter_AddRefs(appRootDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++
++ int levelsToRemove = 0; // In FF21+, appDir points to browser subdirectory.
++#if defined(XP_MACOSX)
++ levelsToRemove += 1;
++#endif
++ while (appRootDir && (levelsToRemove > 0)) {
++ // When crawling up the hierarchy, components named "." do not count.
++ nsAutoCString removedName;
++ rv = appRootDir->GetNativeLeafName(removedName);
++ NS_ENSURE_SUCCESS(rv, rv);
++ bool didRemove = !removedName.Equals(".");
++
++ // Remove a directory component.
++ nsCOMPtr<nsIFile> parentDir;
++ rv = appRootDir->GetParent(getter_AddRefs(parentDir));
++ NS_ENSURE_SUCCESS(rv, rv);
++ appRootDir = parentDir;
++
++ if (didRemove)
++ --levelsToRemove;
++ }
++
++ if (!appRootDir)
++ return NS_ERROR_FAILURE;
++
++ appRootDir.forget(aFile);
++ return NS_OK;
++}
++
++
++nsresult
+ nsXREDirProvider::EnsureDirectoryExists(nsIFile* aDirectory)
+ {
+ bool exists;
+diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h
+index 1985f66..b86cc68 100644
+--- a/toolkit/xre/nsXREDirProvider.h
++++ b/toolkit/xre/nsXREDirProvider.h
+@@ -107,6 +107,7 @@ protected:
+ #if defined(XP_UNIX) || defined(XP_MACOSX)
+ static nsresult GetSystemExtensionsDirectory(nsIFile** aFile);
+ #endif
++ nsresult GetAppRootDir(nsIFile* *aFile);
+ static nsresult EnsureDirectoryExists(nsIFile* aDirectory);
+ void EnsureProfileFileExists(nsIFile* aFile);
+
+diff --git a/tools/update-packaging/common.sh b/tools/update-packaging/common.sh
+index eb35880..96bfa43 100755
+--- a/tools/update-packaging/common.sh
++++ b/tools/update-packaging/common.sh
+@@ -8,7 +8,13 @@
+ # Author: Darin Fisher
+ #
+
++# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
++# we should remove all lines in this file that contain:
++# TorBrowser/Data
++
+ # -----------------------------------------------------------------------------
++QUIET=0
++
+ # By default just assume that these tools exist on our path
+ MAR=${MAR:-mar}
+ BZIP2=${BZIP2:-bzip2}
+@@ -21,6 +27,12 @@ notice() {
+ echo "$*" 1>&2
+ }
+
++verbose_notice() {
++ if [ $QUIET -eq 0 ]; then
++ notice "$*"
++ fi
++}
++
+ get_file_size() {
+ info=($(ls -ln "$1"))
+ echo ${info[4]}
+@@ -54,22 +66,10 @@ make_add_instruction() {
+ forced=
+ fi
+
+- is_extension=$(echo "$f" | grep -c 'distribution/extensions/.*/')
+- if [ $is_extension = "1" ]; then
+- # Use the subdirectory of the extensions folder as the file to test
+- # before performing this add instruction.
+- testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/')
+- notice " add-if \"$testdir\" \"$f\""
+- echo "add-if \"$testdir\" \"$f\"" >> $filev2
+- if [ ! $filev3 = "" ]; then
+- echo "add-if \"$testdir\" \"$f\"" >> $filev3
+- fi
+- else
+- notice " add \"$f\"$forced"
+- echo "add \"$f\"" >> $filev2
+- if [ ! $filev3 = "" ]; then
+- echo "add \"$f\"" >> $filev3
+- fi
++ verbose_notice " add \"$f\"$forced"
++ echo "add \"$f\"" >> "$filev2"
++ if [ ! "$filev3" = "" ]; then
++ echo "add \"$f\"" >> "$filev3"
+ fi
+ }
+
+@@ -100,8 +100,19 @@ make_add_if_not_instruction() {
+ f="$1"
+ filev3="$2"
+
+- notice " add-if-not \"$f\" \"$f\""
+- echo "add-if-not \"$f\" \"$f\"" >> $filev3
++ verbose_notice " add-if-not \"$f\" \"$f\""
++ echo "add-if-not \"$f\" \"$f\"" >> "$filev3"
++}
++
++make_addsymlink_instruction() {
++ link="$1"
++ target="$2"
++ filev2="$3"
++ filev3="$4"
++
++ verbose_notice " addsymlink: $link -> $target"
++ echo "addsymlink \"$link\" \"$target\"" >> "$filev2"
++ echo "addsymlink \"$link\" \"$target\"" >> "$filev3"
+ }
+
+ make_patch_instruction() {
+@@ -109,19 +120,9 @@ make_patch_instruction() {
+ filev2="$2"
+ filev3="$3"
+
+- is_extension=$(echo "$f" | grep -c 'distribution/extensions/.*/')
+- if [ $is_extension = "1" ]; then
+- # Use the subdirectory of the extensions folder as the file to test
+- # before performing this add instruction.
+- testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/')
+- notice " patch-if \"$testdir\" \"$f.patch\" \"$f\""
+- echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> $filev2
+- echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> $filev3
+- else
+- notice " patch \"$f.patch\" \"$f\""
+- echo "patch \"$f.patch\" \"$f\"" >> $filev2
+- echo "patch \"$f.patch\" \"$f\"" >> $filev3
+- fi
++ verbose_notice " patch \"$f.patch\" \"$f\""
++ echo "patch \"$f.patch\" \"$f\"" >> "$filev2"
++ echo "patch \"$f.patch\" \"$f\"" >> "$filev3"
+ }
+
+ append_remove_instructions() {
+@@ -148,19 +149,19 @@ append_remove_instructions() {
+ # Exclude comments
+ if [ ! $(echo "$f" | grep -c '^#') = 1 ]; then
+ if [ $(echo "$f" | grep -c '\/$') = 1 ]; then
+- notice " rmdir \"$f\""
+- echo "rmdir \"$f\"" >> $filev2
+- echo "rmdir \"$f\"" >> $filev3
++ verbose_notice " rmdir \"$f\""
++ echo "rmdir \"$f\"" >> "$filev2"
++ echo "rmdir \"$f\"" >> "$filev3"
+ elif [ $(echo "$f" | grep -c '\/\*$') = 1 ]; then
+ # Remove the *
+ f=$(echo "$f" | sed -e 's:\*$::')
+- notice " rmrfdir \"$f\""
+- echo "rmrfdir \"$f\"" >> $filev2
+- echo "rmrfdir \"$f\"" >> $filev3
++ verbose_notice " rmrfdir \"$f\""
++ echo "rmrfdir \"$f\"" >> "$filev2"
++ echo "rmrfdir \"$f\"" >> "$filev3"
+ else
+- notice " remove \"$f\""
+- echo "remove \"$f\"" >> $filev2
+- echo "remove \"$f\"" >> $filev3
++ verbose_notice " remove \"$f\""
++ echo "remove \"$f\"" >> "$filev2"
++ echo "remove \"$f\"" >> "$filev3"
+ fi
+ fi
+ fi
+@@ -170,6 +171,10 @@ append_remove_instructions() {
+
+ # List all files in the current directory, stripping leading "./"
+ # Pass a variable name and it will be filled as an array.
++# To support Tor Browser updates, skip the following files:
++# TorBrowser/Data/Browser/profiles.ini
++# TorBrowser/Data/Browser/profile.default/bookmarks.html
++# TorBrowser/Data/Tor/torrc
+ list_files() {
+ count=0
+
+@@ -182,6 +187,11 @@ list_files() {
+ | sed 's/\.\/\(.*\)/\1/' \
+ | sort -r > "temp-filelist"
+ while read file; do
++ if [ "$file" = "TorBrowser/Data/Browser/profiles.ini" -o \
++ "$file" = "TorBrowser/Data/Browser/profile.default/bookmarks.html" -o \
++ "$file" = "TorBrowser/Data/Tor/torrc" ]; then
++ continue;
++ fi
+ eval "${1}[$count]=\"$file\""
+ (( count++ ))
+ done < "temp-filelist"
+@@ -203,3 +213,19 @@ list_dirs() {
+ done < "temp-dirlist"
+ rm "temp-dirlist"
+ }
++
++# List all symbolic links in the current directory, stripping leading "./"
++list_symlinks() {
++ count=0
++
++ find . -type l \
++ | sed 's/\.\/\(.*\)/\1/' \
++ | sort -r > "temp-symlinklist"
++ while read symlink; do
++ target=$(readlink "$symlink")
++ eval "${1}[$count]=\"$symlink\""
++ eval "${2}[$count]=\"$target\""
++ (( count++ ))
++ done < "temp-symlinklist"
++ rm "temp-symlinklist"
++}
+diff --git a/tools/update-packaging/make_full_update.sh b/tools/update-packaging/make_full_update.sh
+index f046614..f0bd7f6 100755
+--- a/tools/update-packaging/make_full_update.sh
++++ b/tools/update-packaging/make_full_update.sh
+@@ -28,10 +28,16 @@ if [ $1 = -h ]; then
+ notice ""
+ notice "Options:"
+ notice " -h show this help text"
++ notice " -q be less verbose"
+ notice ""
+ exit 1
+ fi
+
++if [ $1 = -q ]; then
++ QUIET=1
++ shift
++fi
++
+ # -----------------------------------------------------------------------------
+
+ archive="$1"
+@@ -63,17 +69,46 @@ if [ ! -f "precomplete" ]; then
+ fi
+
+ list_files files
++list_symlinks symlinks symlink_targets
++
++# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
++# we should remove the following lines:
++# Make sure we delete the pre 5.1.0 HTTPS Everywhere as well in case it
++# exists. The extension ID got changed with the version bump to 5.1.0.
++ext_path='TorBrowser/Data/Browser/profile.default/extensions'
++if [ -d "$ext_dir" ]; then
++ directories_to_remove="$ext_path/https-everywhere(a)eff.org $ext_path/https-everywhere-eff(a)eff.org"
++else
++ directories_to_remove=""
++fi
++# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+
+ popd
+
+ # Add the type of update to the beginning of the update manifests.
+-> $updatemanifestv2
+-> $updatemanifestv3
++> "$updatemanifestv2"
++> "$updatemanifestv3"
+ notice ""
+ notice "Adding type instruction to update manifests"
+ notice " type complete"
+-echo "type \"complete\"" >> $updatemanifestv2
+-echo "type \"complete\"" >> $updatemanifestv3
++echo "type \"complete\"" >> "$updatemanifestv2"
++echo "type \"complete\"" >> "$updatemanifestv3"
++
++# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
++# we should remove the following lines:
++# If removal of any old, existing directories is desired, emit the appropriate
++# rmrfdir commands.
++notice ""
++notice "Adding directory removal instructions to update manifests"
++for dir_to_remove in $directories_to_remove; do
++ # rmrfdir requires a trailing slash; if slash is missing, add one.
++ if ! [[ "$dir_to_remove" =~ /$ ]]; then
++ dir_to_remove="${dir_to_remove}/"
++ fi
++ echo "rmrfdir \"$dir_to_remove\"" >> "$updatemanifestv2"
++ echo "rmrfdir \"$dir_to_remove\"" >> "$updatemanifestv3"
++done
++# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+
+ notice ""
+ notice "Adding file add instructions to update manifests"
+@@ -99,6 +134,15 @@ for ((i=0; $i<$num_files; i=$i+1)); do
+ targetfiles="$targetfiles \"$f\""
+ done
+
++notice ""
++notice "Adding symlink add instructions to update manifests"
++num_symlinks=${#symlinks[*]}
++for ((i=0; $i<$num_symlinks; i=$i+1)); do
++ link="${symlinks[$i]}"
++ target="${symlink_targets[$i]}"
++ make_addsymlink_instruction "$link" "$target" "$updatemanifestv2" "$updatemanifestv3"
++done
++
+ # Append remove instructions for any dead files.
+ notice ""
+ notice "Adding file and directory remove instructions from file 'removed-files'"
+diff --git a/tools/update-packaging/make_incremental_update.sh b/tools/update-packaging/make_incremental_update.sh
+index 592b7ab..15af172 100755
+--- a/tools/update-packaging/make_incremental_update.sh
++++ b/tools/update-packaging/make_incremental_update.sh
+@@ -21,6 +21,7 @@ print_usage() {
+ notice " -h show this help text"
+ notice " -f clobber this file in the installation"
+ notice " Must be a path to a file to clobber in the partial update."
++ notice " -q be less verbose"
+ notice ""
+ }
+
+@@ -61,6 +62,21 @@ check_for_forced_update() {
+ ## "true" *giggle*
+ return 0;
+ fi
++
++# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
++# we should remove the following lines:
++ # If the file in the skip list ends with /*, do a prefix match.
++ # This allows TorBrowser/Data/Browser/profile.default/extensions/https-everywhere-eff(a)eff.org/*
++ # to be used to force all HTTPS Everywhere files to be updated.
++ f_suffix=${f##*/}
++ if [[ $f_suffix = "*" ]]; then
++ f_prefix="${f%\/\*}";
++ if [[ $forced_file_chk == $f_prefix* ]]; then
++ ## 0 means "true"
++ return 0;
++ fi
++ fi
++# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+ done
+ ## 'false'... because this is bash. Oh yay!
+ return 1;
+@@ -71,13 +87,18 @@ if [ $# = 0 ]; then
+ exit 1
+ fi
+
+-requested_forced_updates='Contents/MacOS/firefox'
++# Firefox uses requested_forced_updates='Contents/MacOS/firefox' due to
++# 770996 but in Tor Browser we do not need that fix.
++requested_forced_updates=""
++directories_to_remove=""
+
+-while getopts "hf:" flag
++while getopts "hqf:" flag
+ do
+ case "$flag" in
+ h) print_usage; exit 0
+ ;;
++ q) QUIET=1
++ ;;
+ f) requested_forced_updates="$requested_forced_updates $OPTARG"
+ ;;
+ ?) print_usage; exit 1
+@@ -104,6 +125,46 @@ updatemanifestv2="$workdir/updatev2.manifest"
+ updatemanifestv3="$workdir/updatev3.manifest"
+ archivefiles="updatev2.manifest updatev3.manifest"
+
++# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
++# we should remove the following lines:
++# If the NoScript or HTTPS Everywhere extensions have changed between
++# releases, add them to the "force updates" list.
++ext_path='TorBrowser/Data/Browser/profile.default/extensions'
++if [ -d "$newdir/$ext_path" ]; then
++ https_everywhere='https-everywhere-eff(a)eff.org'
++ noscript='{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi'
++
++ # NoScript is a packed extension, so we simply compare the old and the new
++ # .xpi files.
++ noscript_path="$ext_path/$noscript"
++ diff -a "$olddir/$noscript_path" "$newdir/$noscript_path" > /dev/null
++ rc=$?
++ if [ $rc -gt 1 ]; then
++ notice "Unexpected exit $rc from $noscript_path diff command"
++ exit 2
++ elif [ $rc -eq 1 ]; then
++ requested_forced_updates="$requested_forced_updates $noscript_path"
++ fi
++
++ # HTTPS Everywhere is an unpacked extension, so we need to determine if any of
++ # the unpacked files have changed. Since that is messy, we simply compare the
++ # old extension's install.rdf file to the new one.
++ https_everywhere_install_rdf="$ext_path/$https_everywhere/install.rdf"
++ diff "$olddir/$https_everywhere_install_rdf" \
++ "$newdir/$https_everywhere_install_rdf" > /dev/null
++ rc=$?
++ if [ $rc -gt 1 -a -e "$olddir/$https_everywhere_install_rdf" ]; then
++ notice "Unexpected exit $rc from $https_everywhere_install_rdf diff command"
++ exit 2
++ elif [ $rc -ge 1 ]; then
++ requested_forced_updates="$requested_forced_updates $ext_path/$https_everywhere/*"
++ # Make sure we delete the pre 5.1.0 HTTPS Everywhere as well in case it
++ # exists. The extension ID got changed with the version bump to 5.1.0.
++ directories_to_remove="$directories_to_remove $ext_path/https-everywhere(a)eff.org $ext_path/$https_everywhere"
++ fi
++fi
++# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
++
+ mkdir -p "$workdir"
+
+ # Generate a list of all files in the target directory.
+@@ -113,6 +174,7 @@ if test $? -ne 0 ; then
+ fi
+
+ list_files oldfiles
++list_symlinks oldsymlinks oldsymlink_targets
+ list_dirs olddirs
+
+ popd
+@@ -131,17 +193,34 @@ fi
+
+ list_dirs newdirs
+ list_files newfiles
++list_symlinks newsymlinks newsymlink_targets
+
+ popd
+
+ # Add the type of update to the beginning of the update manifests.
+ notice ""
+ notice "Adding type instruction to update manifests"
+-> $updatemanifestv2
+-> $updatemanifestv3
++> "$updatemanifestv2"
++> "$updatemanifestv3"
+ notice " type partial"
+-echo "type \"partial\"" >> $updatemanifestv2
+-echo "type \"partial\"" >> $updatemanifestv3
++echo "type \"partial\"" >> "$updatemanifestv2"
++echo "type \"partial\"" >> "$updatemanifestv3"
++
++# TODO When TOR_BROWSER_DATA_OUTSIDE_APP_DIR is used on all platforms,
++# we should remove the following lines:
++# If removal of any old, existing directories is desired, emit the appropriate
++# rmrfdir commands.
++notice ""
++notice "Adding directory removal instructions to update manifests"
++for dir_to_remove in $directories_to_remove; do
++ # rmrfdir requires a trailing slash, so add one if missing.
++ if ! [[ "$dir_to_remove" =~ /$ ]]; then
++ dir_to_remove="${dir_to_remove}/"
++ fi
++ echo "rmrfdir \"$dir_to_remove\"" >> "$updatemanifestv2"
++ echo "rmrfdir \"$dir_to_remove\"" >> "$updatemanifestv3"
++done
++# END TOR_BROWSER_DATA_OUTSIDE_APP_DIR removal
+
+ notice ""
+ notice "Adding file patch and add instructions to update manifests"
+@@ -234,6 +313,24 @@ for ((i=0; $i<$num_oldfiles; i=$i+1)); do
+ fi
+ done
+
++# Remove and re-add symlinks
++notice ""
++notice "Adding symlink remove/add instructions to update manifests"
++num_oldsymlinks=${#oldsymlinks[*]}
++for ((i=0; $i<$num_oldsymlinks; i=$i+1)); do
++ link="${oldsymlinks[$i]}"
++ verbose_notice " remove: $link"
++ echo "remove \"$link\"" >> "$updatemanifestv2"
++ echo "remove \"$link\"" >> "$updatemanifestv3"
++done
++
++num_newsymlinks=${#newsymlinks[*]}
++for ((i=0; $i<$num_newsymlinks; i=$i+1)); do
++ link="${newsymlinks[$i]}"
++ target="${newsymlink_targets[$i]}"
++ make_addsymlink_instruction "$link" "$target" "$updatemanifestv2" "$updatemanifestv3"
++done
++
+ # Newly added files
+ notice ""
+ notice "Adding file add instructions to update manifests"
+@@ -270,8 +367,8 @@ notice "Adding file remove instructions to update manifests"
+ for ((i=0; $i<$num_removes; i=$i+1)); do
+ f="${remove_array[$i]}"
+ notice " remove \"$f\""
+- echo "remove \"$f\"" >> $updatemanifestv2
+- echo "remove \"$f\"" >> $updatemanifestv3
++ echo "remove \"$f\"" >> "$updatemanifestv2"
++ echo "remove \"$f\"" >> "$updatemanifestv3"
+ done
+
+ # Add remove instructions for any dead files.
+@@ -288,8 +385,8 @@ for ((i=0; $i<$num_olddirs; i=$i+1)); do
+ # If this dir doesn't exist in the new directory remove it.
+ if [ ! -d "$newdir/$f" ]; then
+ notice " rmdir $f/"
+- echo "rmdir \"$f/\"" >> $updatemanifestv2
+- echo "rmdir \"$f/\"" >> $updatemanifestv3
++ echo "rmdir \"$f/\"" >> "$updatemanifestv2"
++ echo "rmdir \"$f/\"" >> "$updatemanifestv3"
+ fi
+ done
+
+--
+cgit v0.10.2
+
1
0

28 Jul '16
commit 3b8cae90376092d4926d59c23be2cf7e3b9559db
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Wed Jul 13 13:09:10 2016 -0400
Use the about dialog from Firefox
In addition to copying aboutDialog.xul and making related modifications to the
CSS path (changing "browser" to "instantbird"), this patch also applies the
changes from trac #5698 which has custom settings for Tor Browser.
---
projects/instantbird/about-logo.png | Bin 0 -> 6681 bytes
projects/instantbird/about-logo(a)2x.png | Bin 0 -> 13886 bytes
projects/instantbird/about-wordmark.png | Bin 0 -> 3754 bytes
projects/instantbird/aboutDialog-appUpdater.js | 557 +++++++++++++++++++++++++
projects/instantbird/aboutDialog-jar.patch | 12 +
projects/instantbird/aboutDialog.css | 91 ++++
projects/instantbird/aboutDialog.dtd | 127 ++++++
projects/instantbird/aboutDialog.js | 69 +++
projects/instantbird/aboutDialog.xul | 192 +++++++++
projects/instantbird/branding-aboutDialog.css | 48 +++
projects/instantbird/branding/jar.patch | 11 +
projects/instantbird/build | 11 +-
projects/instantbird/config | 11 +
13 files changed, 1127 insertions(+), 2 deletions(-)
diff --git a/projects/instantbird/about-logo.png b/projects/instantbird/about-logo.png
new file mode 100644
index 0000000..c6e4c49
Binary files /dev/null and b/projects/instantbird/about-logo.png differ
diff --git a/projects/instantbird/about-logo(a)2x.png b/projects/instantbird/about-logo(a)2x.png
new file mode 100644
index 0000000..99d626e
Binary files /dev/null and b/projects/instantbird/about-logo(a)2x.png differ
diff --git a/projects/instantbird/about-wordmark.png b/projects/instantbird/about-wordmark.png
new file mode 100644
index 0000000..52923b6
Binary files /dev/null and b/projects/instantbird/about-wordmark.png differ
diff --git a/projects/instantbird/aboutDialog-appUpdater.js b/projects/instantbird/aboutDialog-appUpdater.js
new file mode 100644
index 0000000..66db02a
--- /dev/null
+++ b/projects/instantbird/aboutDialog-appUpdater.js
@@ -0,0 +1,557 @@
+/* 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/. */
+
+// Note: this file is included in aboutDialog.xul if MOZ_UPDATER is defined.
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
+Components.utils.import("resource://gre/modules/AddonManager.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
+ "resource://gre/modules/UpdateUtils.jsm");
+
+var gAppUpdater;
+
+function onUnload(aEvent) {
+ if (gAppUpdater.isChecking)
+ gAppUpdater.checker.stopChecking(Components.interfaces.nsIUpdateChecker.CURRENT_CHECK);
+ // Safe to call even when there isn't a download in progress.
+ gAppUpdater.removeDownloadListener();
+ gAppUpdater = null;
+}
+
+
+function appUpdater()
+{
+ this.updateDeck = document.getElementById("updateDeck");
+
+ // Hide the update deck when there is already an update window open to avoid
+ // syncing issues between them.
+ if (Services.wm.getMostRecentWindow("Update:Wizard")) {
+ this.updateDeck.hidden = true;
+ return;
+ }
+
+ XPCOMUtils.defineLazyServiceGetter(this, "aus",
+ "@mozilla.org/updates/update-service;1",
+ "nsIApplicationUpdateService");
+ XPCOMUtils.defineLazyServiceGetter(this, "checker",
+ "@mozilla.org/updates/update-checker;1",
+ "nsIUpdateChecker");
+ XPCOMUtils.defineLazyServiceGetter(this, "um",
+ "@mozilla.org/updates/update-manager;1",
+ "nsIUpdateManager");
+
+ this.bundle = Services.strings.
+ createBundle("chrome://browser/locale/browser.properties");
+
+ let manualURL = Services.urlFormatter.formatURLPref("app.update.url.manual");
+ let manualLink = document.getElementById("manualLink");
+ manualLink.value = manualURL;
+ manualLink.href = manualURL;
+ document.getElementById("failedLink").href = manualURL;
+
+ if (this.updateDisabledAndLocked) {
+ this.selectPanel("adminDisabled");
+ return;
+ }
+
+ if (this.isPending || this.isApplied) {
+ this.selectPanel("apply");
+ return;
+ }
+
+ if (this.aus.isOtherInstanceHandlingUpdates) {
+ this.selectPanel("otherInstanceHandlingUpdates");
+ return;
+ }
+
+ if (this.isDownloading) {
+ this.startDownload();
+ // selectPanel("downloading") is called from setupDownloadingUI().
+ return;
+ }
+
+ // Honor the "Never check for updates" option by not only disabling background
+ // update checks, but also in the About dialog, by presenting a
+ // "Check for updates" button.
+ // If updates are found, the user is then asked if he wants to "Update to <version>".
+ if (!this.updateEnabled) {
+ this.selectPanel("checkForUpdates");
+ return;
+ }
+
+ // That leaves the options
+ // "Check for updates, but let me choose whether to install them", and
+ // "Automatically install updates".
+ // In both cases, we check for updates without asking.
+ // In the "let me choose" case, we ask before downloading though, in onCheckComplete.
+ this.checkForUpdates();
+}
+
+appUpdater.prototype =
+{
+ // true when there is an update check in progress.
+ isChecking: false,
+
+ // true when there is an update already staged / ready to be applied.
+ get isPending() {
+ if (this.update) {
+ return this.update.state == "pending" ||
+ this.update.state == "pending-service";
+ }
+ return this.um.activeUpdate &&
+ (this.um.activeUpdate.state == "pending" ||
+ this.um.activeUpdate.state == "pending-service");
+ },
+
+ // true when there is an update already installed in the background.
+ get isApplied() {
+ if (this.update)
+ return this.update.state == "applied" ||
+ this.update.state == "applied-service";
+ return this.um.activeUpdate &&
+ (this.um.activeUpdate.state == "applied" ||
+ this.um.activeUpdate.state == "applied-service");
+ },
+
+ // true when there is an update download in progress.
+ get isDownloading() {
+ if (this.update)
+ return this.update.state == "downloading";
+ return this.um.activeUpdate &&
+ this.um.activeUpdate.state == "downloading";
+ },
+
+ // true when updating is disabled by an administrator.
+ get updateDisabledAndLocked() {
+ return !this.updateEnabled &&
+ Services.prefs.prefIsLocked("app.update.enabled");
+ },
+
+ // true when updating is enabled.
+ get updateEnabled() {
+ try {
+ return Services.prefs.getBoolPref("app.update.enabled");
+ }
+ catch (e) { }
+ return true; // Firefox default is true
+ },
+
+ // true when updating in background is enabled.
+ get backgroundUpdateEnabled() {
+ return this.updateEnabled &&
+ gAppUpdater.aus.canStageUpdates;
+ },
+
+ // true when updating is automatic.
+ get updateAuto() {
+ try {
+ return Services.prefs.getBoolPref("app.update.auto");
+ }
+ catch (e) { }
+ return true; // Firefox default is true
+ },
+
+ /**
+ * Sets the panel of the updateDeck.
+ *
+ * @param aChildID
+ * The id of the deck's child to select, e.g. "apply".
+ */
+ selectPanel: function(aChildID) {
+ let panel = document.getElementById(aChildID);
+
+ let button = panel.querySelector("button");
+ if (button) {
+ if (aChildID == "downloadAndInstall") {
+ let updateVersion = gAppUpdater.update.displayVersion;
+ button.label = this.bundle.formatStringFromName("update.downloadAndInstallButton.label", [updateVersion], 1);
+ button.accessKey = this.bundle.GetStringFromName("update.downloadAndInstallButton.accesskey");
+ }
+ this.updateDeck.selectedPanel = panel;
+ if (!document.commandDispatcher.focusedElement || // don't steal the focus
+ document.commandDispatcher.focusedElement.localName == "button") // except from the other buttons
+ button.focus();
+
+ } else {
+ this.updateDeck.selectedPanel = panel;
+ }
+ },
+
+ /**
+ * Check for updates
+ */
+ checkForUpdates: function() {
+ this.selectPanel("checkingForUpdates");
+ this.isChecking = true;
+ this.checker.checkForUpdates(this.updateCheckListener, true);
+ // after checking, onCheckComplete() is called
+ },
+
+ /**
+ * Check for addon compat, or start the download right away
+ */
+ doUpdate: function() {
+ // skip the compatibility check if the update doesn't provide appVersion,
+ // or the appVersion is unchanged, e.g. nightly update
+ if (!this.update.appVersion ||
+ Services.vc.compare(gAppUpdater.update.appVersion,
+ Services.appinfo.version) == 0) {
+ this.startDownload();
+ } else {
+ this.checkAddonCompatibility();
+ }
+ },
+
+ /**
+ * Handles oncommand for the "Restart to Update" button
+ * which is presented after the download has been downloaded.
+ */
+ buttonRestartAfterDownload: function() {
+ if (!this.isPending && !this.isApplied)
+ return;
+
+ // Notify all windows that an application quit has been requested.
+ let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
+ createInstance(Components.interfaces.nsISupportsPRBool);
+ Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
+
+ // Something aborted the quit process.
+ if (cancelQuit.data)
+ return;
+
+ let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
+ getService(Components.interfaces.nsIAppStartup);
+
+ // If already in safe mode restart in safe mode (bug 327119)
+ if (Services.appinfo.inSafeMode) {
+ appStartup.restartInSafeMode(Components.interfaces.nsIAppStartup.eAttemptQuit);
+ return;
+ }
+
+ appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
+ Components.interfaces.nsIAppStartup.eRestart);
+ },
+
+ /**
+ * Handles oncommand for the "Apply Update…" button
+ * which is presented if we need to show the billboard or license.
+ */
+ buttonApplyBillboard: function() {
+ const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul";
+ var ary = null;
+ ary = Components.classes["@mozilla.org/supports-array;1"].
+ createInstance(Components.interfaces.nsISupportsArray);
+ ary.AppendElement(this.update);
+ var openFeatures = "chrome,centerscreen,dialog=no,resizable=no,titlebar,toolbar=no";
+ Services.ww.openWindow(null, URI_UPDATE_PROMPT_DIALOG, "", openFeatures, ary);
+ window.close(); // close the "About" window; updates.xul takes over.
+ },
+
+ /**
+ * Implements nsIUpdateCheckListener. The methods implemented by
+ * nsIUpdateCheckListener are in a different scope from nsIIncrementalDownload
+ * to make it clear which are used by each interface.
+ */
+ updateCheckListener: {
+ /**
+ * See nsIUpdateService.idl
+ */
+ onCheckComplete: function(aRequest, aUpdates, aUpdateCount) {
+ gAppUpdater.isChecking = false;
+ gAppUpdater.update = gAppUpdater.aus.
+ selectUpdate(aUpdates, aUpdates.length);
+ if (!gAppUpdater.update) {
+ gAppUpdater.selectPanel("noUpdatesFound");
+ return;
+ }
+
+ if (gAppUpdater.update.unsupported) {
+ if (gAppUpdater.update.detailsURL) {
+ let unsupportedLink = document.getElementById("unsupportedLink");
+ unsupportedLink.href = gAppUpdater.update.detailsURL;
+ }
+ gAppUpdater.selectPanel("unsupportedSystem");
+ return;
+ }
+
+ if (!gAppUpdater.aus.canApplyUpdates) {
+ gAppUpdater.selectPanel("manualUpdate");
+ return;
+ }
+
+ // Firefox no longer displays a license for updates and the licenseURL
+ // check is just in case a distibution does.
+ if (gAppUpdater.update.billboardURL || gAppUpdater.update.licenseURL) {
+ gAppUpdater.selectPanel("applyBillboard");
+ return;
+ }
+
+ if (gAppUpdater.updateAuto) // automatically download and install
+ gAppUpdater.doUpdate();
+ else // ask
+ gAppUpdater.selectPanel("downloadAndInstall");
+ },
+
+ /**
+ * See nsIUpdateService.idl
+ */
+ onError: function(aRequest, aUpdate) {
+ // Errors in the update check are treated as no updates found. If the
+ // update check fails repeatedly without a success the user will be
+ // notified with the normal app update user interface so this is safe.
+ gAppUpdater.isChecking = false;
+ gAppUpdater.selectPanel("noUpdatesFound");
+ },
+
+ /**
+ * See nsISupports.idl
+ */
+ QueryInterface: function(aIID) {
+ if (!aIID.equals(Components.interfaces.nsIUpdateCheckListener) &&
+ !aIID.equals(Components.interfaces.nsISupports))
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ return this;
+ }
+ },
+
+ /**
+ * Checks the compatibility of add-ons for the application update.
+ */
+ checkAddonCompatibility: function() {
+ try {
+ var hotfixID = Services.prefs.getCharPref(PREF_EM_HOTFIX_ID);
+ }
+ catch (e) { }
+
+ var self = this;
+ AddonManager.getAllAddons(function(aAddons) {
+ self.addons = [];
+ self.addonsCheckedCount = 0;
+ aAddons.forEach(function(aAddon) {
+ // Protect against code that overrides the add-ons manager and doesn't
+ // implement the isCompatibleWith or the findUpdates method.
+ if (!("isCompatibleWith" in aAddon) || !("findUpdates" in aAddon)) {
+ let errMsg = "Add-on doesn't implement either the isCompatibleWith " +
+ "or the findUpdates method!";
+ if (aAddon.id)
+ errMsg += " Add-on ID: " + aAddon.id;
+ Components.utils.reportError(errMsg);
+ return;
+ }
+
+ // If an add-on isn't appDisabled and isn't userDisabled then it is
+ // either active now or the user expects it to be active after the
+ // restart. If that is the case and the add-on is not installed by the
+ // application and is not compatible with the new application version
+ // then the user should be warned that the add-on will become
+ // incompatible. If an addon's type equals plugin it is skipped since
+ // checking plugins compatibility information isn't supported and
+ // getting the scope property of a plugin breaks in some environments
+ // (see bug 566787). The hotfix add-on is also ignored as it shouldn't
+ // block the user from upgrading.
+ try {
+ if (aAddon.type != "plugin" && aAddon.id != hotfixID &&
+ !aAddon.appDisabled && !aAddon.userDisabled &&
+ aAddon.scope != AddonManager.SCOPE_APPLICATION &&
+ aAddon.isCompatible &&
+ !aAddon.isCompatibleWith(self.update.appVersion,
+ self.update.platformVersion))
+ self.addons.push(aAddon);
+ }
+ catch (e) {
+ Components.utils.reportError(e);
+ }
+ });
+ self.addonsTotalCount = self.addons.length;
+ if (self.addonsTotalCount == 0) {
+ self.startDownload();
+ return;
+ }
+
+ self.checkAddonsForUpdates();
+ });
+ },
+
+ /**
+ * Checks if there are updates for add-ons that are incompatible with the
+ * application update.
+ */
+ checkAddonsForUpdates: function() {
+ this.addons.forEach(function(aAddon) {
+ aAddon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_DETECTED,
+ this.update.appVersion,
+ this.update.platformVersion);
+ }, this);
+ },
+
+ /**
+ * See XPIProvider.jsm
+ */
+ onCompatibilityUpdateAvailable: function(aAddon) {
+ for (var i = 0; i < this.addons.length; ++i) {
+ if (this.addons[i].id == aAddon.id) {
+ this.addons.splice(i, 1);
+ break;
+ }
+ }
+ },
+
+ /**
+ * See XPIProvider.jsm
+ */
+ onUpdateAvailable: function(aAddon, aInstall) {
+ if (!Services.blocklist.isAddonBlocklisted(aAddon,
+ this.update.appVersion,
+ this.update.platformVersion)) {
+ // Compatibility or new version updates mean the same thing here.
+ this.onCompatibilityUpdateAvailable(aAddon);
+ }
+ },
+
+ /**
+ * See XPIProvider.jsm
+ */
+ onUpdateFinished: function(aAddon) {
+ ++this.addonsCheckedCount;
+
+ if (this.addonsCheckedCount < this.addonsTotalCount)
+ return;
+
+ if (this.addons.length == 0) {
+ // Compatibility updates or new version updates were found for all add-ons
+ this.startDownload();
+ return;
+ }
+
+ this.selectPanel("applyBillboard");
+ },
+
+ /**
+ * Starts the download of an update mar.
+ */
+ startDownload: function() {
+ if (!this.update)
+ this.update = this.um.activeUpdate;
+ this.update.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
+ this.update.setProperty("foregroundDownload", "true");
+
+ this.aus.pauseDownload();
+ let state = this.aus.downloadUpdate(this.update, false);
+ if (state == "failed") {
+ this.selectPanel("downloadFailed");
+ return;
+ }
+
+ this.setupDownloadingUI();
+ },
+
+ /**
+ * Switches to the UI responsible for tracking the download.
+ */
+ setupDownloadingUI: function() {
+ this.downloadStatus = document.getElementById("downloadStatus");
+ this.downloadStatus.value =
+ DownloadUtils.getTransferTotal(0, this.update.selectedPatch.size);
+ this.selectPanel("downloading");
+ this.aus.addDownloadListener(this);
+ },
+
+ removeDownloadListener: function() {
+ if (this.aus) {
+ this.aus.removeDownloadListener(this);
+ }
+ },
+
+ /**
+ * See nsIRequestObserver.idl
+ */
+ onStartRequest: function(aRequest, aContext) {
+ },
+
+ /**
+ * See nsIRequestObserver.idl
+ */
+ onStopRequest: function(aRequest, aContext, aStatusCode) {
+ switch (aStatusCode) {
+ case Components.results.NS_ERROR_UNEXPECTED:
+ if (this.update.selectedPatch.state == "download-failed" &&
+ (this.update.isCompleteUpdate || this.update.patchCount != 2)) {
+ // Verification error of complete patch, informational text is held in
+ // the update object.
+ this.removeDownloadListener();
+ this.selectPanel("downloadFailed");
+ break;
+ }
+ // Verification failed for a partial patch, complete patch is now
+ // downloading so return early and do NOT remove the download listener!
+ break;
+ case Components.results.NS_BINDING_ABORTED:
+ // Do not remove UI listener since the user may resume downloading again.
+ break;
+ case Components.results.NS_OK:
+ this.removeDownloadListener();
+ if (this.backgroundUpdateEnabled) {
+ this.selectPanel("applying");
+ let update = this.um.activeUpdate;
+ let self = this;
+ Services.obs.addObserver(function (aSubject, aTopic, aData) {
+ // Update the UI when the background updater is finished
+ let status = aData;
+ if (status == "applied" || status == "applied-service" ||
+ status == "pending" || status == "pending-service") {
+ // If the update is successfully applied, or if the updater has
+ // fallen back to non-staged updates, show the "Restart to Update"
+ // button.
+ self.selectPanel("apply");
+ } else if (status == "failed") {
+ // Background update has failed, let's show the UI responsible for
+ // prompting the user to update manually.
+ self.selectPanel("downloadFailed");
+ } else if (status == "downloading") {
+ // We've fallen back to downloading the full update because the
+ // partial update failed to get staged in the background.
+ // Therefore we need to keep our observer.
+ self.setupDownloadingUI();
+ return;
+ }
+ Services.obs.removeObserver(arguments.callee, "update-staged");
+ }, "update-staged", false);
+ } else {
+ this.selectPanel("apply");
+ }
+ break;
+ default:
+ this.removeDownloadListener();
+ this.selectPanel("downloadFailed");
+ break;
+ }
+ },
+
+ /**
+ * See nsIProgressEventSink.idl
+ */
+ onStatus: function(aRequest, aContext, aStatus, aStatusArg) {
+ },
+
+ /**
+ * See nsIProgressEventSink.idl
+ */
+ onProgress: function(aRequest, aContext, aProgress, aProgressMax) {
+ this.downloadStatus.value =
+ DownloadUtils.getTransferTotal(aProgress, aProgressMax);
+ },
+
+ /**
+ * See nsISupports.idl
+ */
+ QueryInterface: function(aIID) {
+ if (!aIID.equals(Components.interfaces.nsIProgressEventSink) &&
+ !aIID.equals(Components.interfaces.nsIRequestObserver) &&
+ !aIID.equals(Components.interfaces.nsISupports))
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ return this;
+ }
+};
diff --git a/projects/instantbird/aboutDialog-jar.patch b/projects/instantbird/aboutDialog-jar.patch
new file mode 100644
index 0000000..91f13bf
--- /dev/null
+++ b/projects/instantbird/aboutDialog-jar.patch
@@ -0,0 +1,12 @@
+diff --git a/im/content/jar.mn b/im/content/jar.mn
+--- a/im/content/jar.mn
++++ b/im/content/jar.mn
+@@ -10,6 +10,8 @@
+ #endif
+ content/instantbird/aboutDialog.css
+ * content/instantbird/aboutDialog.xul
++ content/instantbird/aboutDialog.js
++ content/instantbird/aboutDialog-appUpdater.js
+ content/instantbird/aboutPanel.xml
+ content/instantbird/account.js
+ content/instantbird/accounts.css
diff --git a/projects/instantbird/aboutDialog.css b/projects/instantbird/aboutDialog.css
new file mode 100644
index 0000000..a065c8e
--- /dev/null
+++ b/projects/instantbird/aboutDialog.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/. */
+
+#aboutDialog {
+ width: 620px;
+}
+
+#rightBox {
+ background-image: url("chrome://branding/content/about-wordmark.png");
+ background-position: left top;
+ background-repeat: no-repeat;
+ /* padding-top creates room for the wordmark */
+ padding-top: 38px;
+ margin-top:20px;
+}
+
+#rightBox:-moz-locale-dir(rtl) {
+ background-position: 100% 0;
+}
+
+#bottomBox > hbox:not(#newBottom) {
+ display: none;
+}
+
+#version {
+ font-weight: bold;
+ margin-top: 10px;
+ -moz-margin-start: 0;
+ -moz-user-select: text;
+ -moz-user-focus: normal;
+ cursor: text;
+}
+
+#version:-moz-locale-dir(rtl) {
+ direction: ltr;
+ text-align: right;
+ margin-right: 0;
+}
+
+#distribution,
+#distributionId {
+ display: none;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.text-blurb {
+ margin-bottom: 10px;
+ -moz-margin-start: 0;
+ -moz-padding-start: 0;
+}
+
+#updateButton,
+#updateDeck > hbox > label {
+ -moz-margin-start: 0;
+ -moz-padding-start: 0;
+}
+
+.update-throbber {
+ width: 16px;
+ min-height: 16px;
+ -moz-margin-end: 3px;
+ list-style-image: url("chrome://global/skin/icons/loading_16.png");
+}
+
+.text-link,
+.text-link:focus {
+ margin: 0px;
+ padding: 0px;
+}
+
+.bottom-link,
+.bottom-link:focus {
+ text-align: center;
+ margin: 0 40px;
+}
+
+#currentChannel {
+ margin: 0;
+ padding: 0;
+ font-weight: bold;
+}
+
+#trademarkTor {
+ font-size: xx-small;
+ text-align: center;
+ color: #999999;
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
diff --git a/projects/instantbird/aboutDialog.dtd b/projects/instantbird/aboutDialog.dtd
new file mode 100644
index 0000000..1562ebc
--- /dev/null
+++ b/projects/instantbird/aboutDialog.dtd
@@ -0,0 +1,127 @@
+<!-- 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/. -->
+<!ENTITY aboutDialog.title "About &brandFullName;">
+
+<!-- LOCALIZATION NOTE (update.checkForUpdatesButton.*, update.updateButton.*, update.applyButtonBillboard.*):
+# Only one button is present at a time.
+# The button when displayed is located directly under the Firefox version in
+# the about dialog (see bug 596813 for screenshots).
+-->
+<!ENTITY update.checkForUpdatesButton.label "Check for updates">
+<!ENTITY update.checkForUpdatesButton.accesskey "C">
+<!ENTITY update.updateButton.label2 "Restart &brandShortName; to Update">
+<!ENTITY update.updateButton.accesskey "R">
+<!ENTITY update.applyButtonBillboard.label "Apply Update…">
+<!ENTITY update.applyButtonBillboard.accesskey "A">
+
+
+<!-- LOCALIZATION NOTE (warningDesc.version): This is a warning about the experimental nature of Nightly and Aurora builds. It is only shown in those versions. -->
+<!ENTITY warningDesc.version "&brandShortName; is experimental and may be unstable.">
+<!-- LOCALIZATION NOTE (warningDesc.telemetryDesc): This is a notification that Nightly/Aurora builds automatically send Telemetry data back to Mozilla. It is only shown in those versions. "It" refers to brandShortName. -->
+<!ENTITY warningDesc.telemetryDesc "It automatically sends information about performance, hardware, usage and customizations back to &vendorShortName; to help make &brandShortName; better.">
+
+<!-- LOCALIZATION NOTE (community.exp.*) This paragraph is shown in "experimental" builds, i.e. Nightly and Aurora builds, instead of the other "community.*" strings below. -->
+<!ENTITY community.exp.start "">
+<!-- LOCALIZATION NOTE (community.exp.mozillaLink): This is a link title that links to http://www.mozilla.org/. -->
+<!ENTITY community.exp.mozillaLink "&vendorShortName;">
+<!ENTITY community.exp.middle " is a ">
+<!-- LOCALIZATION NOTE (community.exp.creditslink): This is a link title that links to about:credits. -->
+<!ENTITY community.exp.creditsLink "global community">
+<!ENTITY community.exp.end " working together to keep the Web open, public and accessible to all.">
+
+<!ENTITY community.start2 "&brandShortName; is designed by ">
+<!-- LOCALIZATION NOTE (community.mozillaLink): This is a link title that links to http://www.mozilla.org/. -->
+<!ENTITY community.mozillaLink "&vendorShortName;">
+<!ENTITY community.middle2 ", a ">
+<!-- LOCALIZATION NOTE (community.creditsLink): This is a link title that links to about:credits. -->
+<!ENTITY community.creditsLink "global community">
+<!ENTITY community.end3 " working together to keep the Web open, public and accessible to all.">
+
+<!ENTITY helpus.start "Want to help? ">
+<!-- LOCALIZATION NOTE (helpus.donateLink): This is a link title that links to https://sendto.mozilla.org/page/contribute/Give-Now?source=mozillaorg_defau…. -->
+<!ENTITY helpus.donateLink "Make a donation">
+<!ENTITY helpus.middle " or ">
+<!-- LOCALIZATION NOTE (helpus.getInvolvedLink): This is a link title that links to http://www.mozilla.org/contribute/. -->
+<!ENTITY helpus.getInvolvedLink "get involved!">
+<!ENTITY helpus.end "">
+
+<!-- LOCALIZATION NOTE (bottomLinks.license): This is a link title that links to about:license. -->
+<!ENTITY bottomLinks.license "Licensing Information">
+
+<!-- LOCALIZATION NOTE (bottomLinks.rights): This is a link title that links to about:rights. -->
+<!ENTITY bottomLinks.rights "End-User Rights">
+
+<!-- LOCALIZATION NOTE (bottomLinks.privacy): This is a link title that links to https://www.mozilla.org/legal/privacy/. -->
+<!ENTITY bottomLinks.privacy "Privacy Policy">
+
+<!-- LOCALIZATION NOTE (update.checkingForUpdates): try to make the localized text short (see bug 596813 for screenshots). -->
+<!ENTITY update.checkingForUpdates "Checking for updates…">
+<!-- LOCALIZATION NOTE (update.noUpdatesFound): try to make the localized text short (see bug 596813 for screenshots). -->
+<!ENTITY update.noUpdatesFound "&brandShortName; is up to date">
+<!-- LOCALIZATION NOTE (update.adminDisabled): try to make the localized text short (see bug 596813 for screenshots). -->
+<!ENTITY update.adminDisabled "Updates disabled by your system administrator">
+<!-- LOCALIZATION NOTE (update.otherInstanceHandlingUpdates): try to make the localized text short -->
+<!ENTITY update.otherInstanceHandlingUpdates "&brandShortName; is being updated by another instance">
+
+<!-- LOCALIZATION NOTE (update.failed.start,update.failed.linkText,update.failed.end):
+ update.failed.start, update.failed.linkText, and update.failed.end all go into
+ one line with linkText being wrapped in an anchor that links to a site to download
+ the latest version of Firefox (e.g. http://www.firefox.com) As this is all in
+ one line, try to make the localized text short (see bug 596813 for screenshots). -->
+<!ENTITY update.failed.start "Update failed. ">
+<!ENTITY update.failed.linkText "Download the latest version">
+<!ENTITY update.failed.end "">
+
+<!-- LOCALIZATION NOTE (update.manual.start,update.manual.end): update.manual.start and update.manual.end
+ all go into one line and have an anchor in between with text that is the same as the link to a site
+ to download the latest version of Firefox (e.g. http://www.firefox.com) As this is all in one line,
+ try to make the localized text short (see bug 596813 for screenshots). -->
+<!ENTITY update.manual.start "Updates available at ">
+<!ENTITY update.manual.end "">
+
+<!-- LOCALIZATION NOTE (update.unsupported.start,update.unsupported.linkText,update.unsupported.end):
+ update.unsupported.start, update.unsupported.linkText, and
+ update.unsupported.end all go into one line with linkText being wrapped in
+ an anchor that links to a site to provide additional information regarding
+ why the system is no longer supported. As this is all in one line, try to
+ make the localized text short (see bug 843497 for screenshots). -->
+<!ENTITY update.unsupported.start "You can not perform further updates on this system. ">
+<!ENTITY update.unsupported.linkText "Learn more">
+<!ENTITY update.unsupported.end "">
+
+<!-- LOCALIZATION NOTE (update.downloading.start,update.downloading.end): update.downloading.start and
+ update.downloading.end all go into one line, with the amount downloaded inserted in between. As this
+ is all in one line, try to make the localized text short (see bug 596813 for screenshots). The — is
+ the "em dash" (long dash).
+ example: Downloading update — 111 KB of 13 MB -->
+<!ENTITY update.downloading.start "Downloading update — ">
+<!ENTITY update.downloading.end "">
+
+<!ENTITY update.applying "Applying update…">
+
+<!-- LOCALIZATION NOTE (channel.description.start,channel.description.end): channel.description.start and
+ channel.description.end create one sentence, with the current channel label inserted in between.
+ example: You are currently on the _Stable_ update channel. -->
+<!ENTITY channel.description.start "You are currently on the ">
+<!ENTITY channel.description.end " update channel. ">
+
+<!ENTITY project.start "&brandShortName; is developed by ">
+<!-- LOCALIZATION NOTE (project.tpoLink): This is a link title that links to https://www.torproject.org -->
+<!ENTITY project.tpoLink "the &vendorShortName;">
+<!ENTITY project.end ", a nonprofit working to defend your privacy and freedom online.">
+
+<!ENTITY help.start "Want to help? ">
+<!-- LOCALIZATION NOTE (help.donate): This is a link title that links to https://www.torproject.org/donate/donate.html.en -->
+<!ENTITY help.donateLink "Donate">
+<!ENTITY help.or " or ">
+<!-- LOCALIZATION NOTE (help.getInvolvedLink): This is a link title that links to https://www.torproject.org/getinvolved/volunteer.html.en -->
+<!ENTITY help.getInvolvedLink "get involved">
+<!ENTITY help.end "!">
+<!-- LOCALIZATION NOTE (bottom.questions): This is a link title that links to https://www.torproject.org/docs/trademark-faq.html.en -->
+<!ENTITY bottomLinks.questions "Questions?">
+<!-- LOCALIZATION NOTE (bottom.questions): This is a link title that links to https://www.torproject.org/getinvolved/relays -->
+<!ENTITY bottomLinks.grow "Help the Tor Network Grow!">
+<!-- LOCALIZATION NOTE (bottom.questions): This is a link title that links to about:license -->
+<!ENTITY bottomLinks.license "Licensing Information">
+<!ENTITY tor.TrademarkStatement "'Tor' and the 'Onion Logo' are registered trademarks of the Tor Project, Inc.">
diff --git a/projects/instantbird/aboutDialog.js b/projects/instantbird/aboutDialog.js
new file mode 100644
index 0000000..55043af
--- /dev/null
+++ b/projects/instantbird/aboutDialog.js
@@ -0,0 +1,69 @@
+/* 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/. */
+
+// Services = object with smart getters for common XPCOM services
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/AppConstants.jsm");
+
+const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
+
+function init(aEvent)
+{
+ if (aEvent.target != document)
+ return;
+
+ try {
+ var distroId = Services.prefs.getCharPref("distribution.id");
+ if (distroId) {
+ var distroVersion = Services.prefs.getCharPref("distribution.version");
+
+ var distroIdField = document.getElementById("distributionId");
+ distroIdField.value = distroId + " - " + distroVersion;
+ distroIdField.style.display = "block";
+
+ try {
+ // This is in its own try catch due to bug 895473 and bug 900925.
+ var distroAbout = Services.prefs.getComplexValue("distribution.about",
+ Components.interfaces.nsISupportsString);
+ var distroField = document.getElementById("distribution");
+ distroField.value = distroAbout;
+ distroField.style.display = "block";
+ }
+ catch (ex) {
+ // Pref is unset
+ Components.utils.reportError(ex);
+ }
+ }
+ }
+ catch (e) {
+ // Pref is unset
+ }
+
+ // Include the build ID and display warning if this is an "a#" (nightly or aurora) build
+ let version = Services.appinfo.version;
+ if (/a\d+$/.test(version)) {
+ let buildID = Services.appinfo.appBuildID;
+ let buildDate = buildID.slice(0,4) + "-" + buildID.slice(4,6) + "-" + buildID.slice(6,8);
+ document.getElementById("version").textContent += " (" + buildDate + ")";
+ document.getElementById("experimental").hidden = false;
+ document.getElementById("communityDesc").hidden = true;
+ }
+
+ if (AppConstants.MOZ_UPDATER) {
+ gAppUpdater = new appUpdater();
+
+ let defaults = Services.prefs.getDefaultBranch("");
+ let channelLabel = document.getElementById("currentChannel");
+ let currentChannelText = document.getElementById("currentChannelText");
+ channelLabel.value = UpdateUtils.UpdateChannel;
+ if (/^release($|\-)/.test(channelLabel.value))
+ currentChannelText.hidden = true;
+ }
+
+ if (AppConstants.platform == "macosx") {
+ // it may not be sized at this point, and we need its width to calculate its position
+ window.sizeToContent();
+ window.moveTo((screen.availWidth / 2) - (window.outerWidth / 2), screen.availHeight / 5);
+ }
+}
diff --git a/projects/instantbird/aboutDialog.xul b/projects/instantbird/aboutDialog.xul
new file mode 100644
index 0000000..642dce4
--- /dev/null
+++ b/projects/instantbird/aboutDialog.xul
@@ -0,0 +1,192 @@
+<?xml version="1.0"?> <!-- -*- Mode: HTML -*- -->
+
+# 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/.
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://instantbird/content/aboutDialog.css" type="text/css"?>
+<?xml-stylesheet href="chrome://branding/content/aboutDialog.css" type="text/css"?>
+
+<!DOCTYPE window [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+%brandDTD;
+<!ENTITY % aboutDialogDTD SYSTEM "chrome://instantbird/locale/aboutDialog.dtd" >
+%aboutDialogDTD;
+]>
+
+#ifdef XP_MACOSX
+<?xul-overlay href="chrome://instantbird/content/macBrowserOverlay.xul"?>
+#endif
+
+<window xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ id="aboutDialog"
+ windowtype="Browser:About"
+ onload="init(event);"
+#ifdef MOZ_UPDATER
+ onunload="onUnload(event);"
+#endif
+#ifdef XP_MACOSX
+ inwindowmenu="false"
+#else
+ title="&aboutDialog.title;"
+#endif
+ role="dialog"
+ aria-describedby="version distribution distributionId communityDesc contributeDesc trademark"
+ >
+
+ <script type="application/javascript" src="chrome://instantbird/content/aboutDialog.js"/>
+#ifdef MOZ_UPDATER
+ <script type="application/javascript" src="chrome://instantbird/content/aboutDialog-appUpdater.js"/>
+#endif
+ <vbox id="aboutDialogContainer">
+ <hbox id="clientBox">
+ <vbox id="leftBox" flex="1"/>
+ <vbox id="rightBox" flex="1">
+#expand <label id="version">__MOZ_APP_VERSION_DISPLAY__</label>
+ <label id="distribution" class="text-blurb"/>
+ <label id="distributionId" class="text-blurb"/>
+
+ <vbox id="detailsBox">
+ <vbox id="updateBox">
+#ifdef MOZ_UPDATER
+ <deck id="updateDeck" orient="vertical">
+ <hbox id="checkForUpdates" align="center">
+ <button id="checkForUpdatesButton" align="start"
+ label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ oncommand="gAppUpdater.checkForUpdates();"/>
+ <spacer flex="1"/>
+ </hbox>
+ <hbox id="downloadAndInstall" align="center">
+ <button id="downloadAndInstallButton" align="start"
+ oncommand="gAppUpdater.doUpdate();"/>
+ <!-- label and accesskey will be filled by JS -->
+ <spacer flex="1"/>
+ </hbox>
+ <hbox id="apply" align="center">
+ <button id="updateButton" align="start"
+ label="&update.updateButton.label2;"
+ accesskey="&update.updateButton.accesskey;"
+ oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
+ <spacer flex="1"/>
+ </hbox>
+ <hbox id="applyBillboard" align="center">
+ <button id="applyButtonBillboard" align="start"
+ label="&update.applyButtonBillboard.label;"
+ accesskey="&update.applyButtonBillboard.accesskey;"
+ oncommand="gAppUpdater.buttonApplyBillboard();"/>
+ <spacer flex="1"/>
+ </hbox>
+ <hbox id="checkingForUpdates" align="center">
+ <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
+ </hbox>
+ <hbox id="downloading" align="center">
+ <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
+ </hbox>
+ <hbox id="applying" align="center">
+ <image class="update-throbber"/><label>&update.applying;</label>
+ </hbox>
+ <hbox id="downloadFailed" align="center">
+ <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
+ </hbox>
+ <hbox id="adminDisabled" align="center">
+ <label>&update.adminDisabled;</label>
+ </hbox>
+ <hbox id="noUpdatesFound" align="center">
+ <label>&update.noUpdatesFound;</label>
+ </hbox>
+ <hbox id="otherInstanceHandlingUpdates" align="center">
+ <label>&update.otherInstanceHandlingUpdates;</label>
+ </hbox>
+ <hbox id="manualUpdate" align="center">
+ <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
+ </hbox>
+ <hbox id="unsupportedSystem" align="center">
+ <label>&update.unsupported.start;</label><label id="unsupportedLink" class="text-link">&update.unsupported.linkText;</label><label>&update.unsupported.end;</label>
+ </hbox>
+ </deck>
+#endif
+ <description class="text-blurb" id="projectDesc">
+ &project.start;
+ <label class="text-link"
+ href="https://www.torproject.org/">
+ &project.tpoLink;
+ </label>&project.end;
+ </description>
+ <description class="text-blurb" id="helpDesc">
+ &help.start;
+ <label class="text-link"
+ href="https://www.torproject.org/donate/donate.html.en">
+ &help.donateLink;
+ </label>
+ &help.or;
+ <label class="text-link"
+ href="https://www.torproject.org/getinvolved/volunteer.html.en">
+ &help.getInvolvedLink;
+ </label>&help.end;
+ </description>
+ </vbox>
+
+#ifdef MOZ_UPDATER
+ <description class="text-blurb" id="currentChannelText">
+ &channel.description.start;<label id="currentChannel"/>&channel.description.end;
+ </description>
+#endif
+ <vbox id="experimental" hidden="true">
+ <description class="text-blurb" id="warningDesc">
+ &warningDesc.version;
+#ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
+ &warningDesc.telemetryDesc;
+#endif
+ </description>
+ <description class="text-blurb" id="communityExperimentalDesc">
+ &community.exp.start;<label class="text-link" href="http://www.mozilla.org/">&community.exp.mozillaLink;</label>&community.exp.middle;<label class="text-link" href="about:credits">&community.exp.creditsLink;</label>&community.exp.end;
+ </description>
+ </vbox>
+ <description class="text-blurb" id="communityDesc">
+ &community.start2;<label class="text-link" href="http://www.mozilla.org/">&community.mozillaLink;</label>&community.middle2;<label class="text-link" href="about:credits">&community.creditsLink;</label>&community.end3;
+ </description>
+ <description class="text-blurb" id="contributeDesc">
+ &helpus.start;<label class="text-link" href="https://sendto.mozilla.org/page/contribute/Give-Now?source=mozillaorg_defau…">&helpus.donateLink;</label>&helpus.middle;<label class="text-link" href="http://www.mozilla.org/contribute/">&helpus.getInvolvedLink;</label>&helpus.end;
+ </description>
+ </vbox>
+ </vbox>
+ </hbox>
+ <vbox id="bottomBox">
+ <hbox pack="center">
+ <label class="text-link bottom-link" href="about:license">&bottomLinks.license;</label>
+ <label class="text-link bottom-link" href="about:rights">&bottomLinks.rights;</label>
+ <label class="text-link bottom-link" href="https://www.mozilla.org/privacy/">&bottomLinks.privacy;</label>
+ </hbox>
+ <description id="trademark">&trademarkInfo.part1;</description>
+ </vbox>
+ <hbox id="newBottom" pack="center" position="1">
+ <label class="text-link bottom-link"
+ href="https://www.torproject.org/docs/faq.html.en">
+ &bottomLinks.questions;
+ </label>
+ <label class="text-link bottom-link"
+ href="https://www.torproject.org/getinvolved/relays">
+ &bottomLinks.grow;
+ </label>
+ <label class="text-link bottom-link"
+ href="about:license">
+ &bottomLinks.license;
+ </label>
+ </hbox>
+ <description id="trademarkTor" insertafter="trademark">
+ &tor.TrademarkStatement;
+ </description>
+
+ </vbox>
+
+ <keyset>
+ <key keycode="VK_ESCAPE" oncommand="window.close();"/>
+ </keyset>
+
+#ifdef XP_MACOSX
+#include browserMountPoints.inc
+#endif
+</window>
diff --git a/projects/instantbird/branding-aboutDialog.css b/projects/instantbird/branding-aboutDialog.css
new file mode 100644
index 0000000..9a3c04e
--- /dev/null
+++ b/projects/instantbird/branding-aboutDialog.css
@@ -0,0 +1,48 @@
+/* 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/. */
+
+#clientBox {
+ background-color: #F7F7F7;
+ color: #222222;
+}
+
+#leftBox {
+ background-image: url("chrome://branding/content/about-logo.png");
+ background-position: right top;
+ background-repeat: no-repeat;
+ background-size: 180px;
+ /* min-width and min-height create room for the logo */
+ min-width: 210px;
+ min-height: 210px;
+ margin-top: 20px;
+ -moz-margin-start: 30px;
+}
+
+
+@media (min-resolution: 2dppx) {
+ #leftBox {
+ background-image: url("chrome://branding/content/about-logo@2x.png");
+ }
+}
+
+#rightBox {
+ margin-left: 30px;
+ margin-right: 30px;
+}
+
+#updateDeck > hbox > label:not([class="text-link"]) {
+ color: #909090;
+}
+
+#trademark {
+ display: none;
+}
+
+#contributeDesc {
+ display: none;
+}
+
+#communityDesc {
+ display: none;
+}
diff --git a/projects/instantbird/branding/jar.patch b/projects/instantbird/branding/jar.patch
new file mode 100644
index 0000000..7254d77
--- /dev/null
+++ b/projects/instantbird/branding/jar.patch
@@ -0,0 +1,11 @@
+diff --git a/im/branding/messenger/jar.mn b/im/branding/messenger/jar.mn
+--- a/im/branding/messenger/jar.mn
++++ b/im/branding/messenger/jar.mn
+@@ -8,3 +8,7 @@
+ content/branding/about-footer.png (content/about-footer.png)
+ content/branding/about.png (content/about.png)
+ content/branding/icon64.png (content/icon64.png)
++ content/branding/aboutDialog.css (content/aboutDialog.css)
++ content/branding/about-logo.png (content/about-logo.png)
++ content/branding/about-logo(a)2x.png (content/about-logo(a)2x.png)
++ content/branding/about-wordmark.png (content/about-wordmark.png)
diff --git a/projects/instantbird/build b/projects/instantbird/build
index 7c4c211..1b8b058 100644
--- a/projects/instantbird/build
+++ b/projects/instantbird/build
@@ -69,9 +69,16 @@ cp $rootdir/branding/default.ico im/branding/messenger/windows/
cp $rootdir/branding/instantbird.ico im/branding/messenger/
cp $rootdir/branding/instantbird.icns im/branding/messenger/
-cp $rootdir/branding/about.png im/branding/messenger/content/
+cp $rootdir/about-logo.png im/branding/messenger/content/
+cp $rootdir/about-logo(a)2x.png im/branding/messenger/content/
+cp $rootdir/about-wordmark.png im/branding/messenger/content/
-echo '<!ENTITY tmVersion "[% c('var/tormessenger_version') %]">' >> im/locales/en-US/chrome/instantbird/aboutDialog.dtd
+cp $rootdir/branding-aboutDialog.css im/branding/messenger/content/aboutDialog.css
+
+rm im/content/aboutDialog*
+
+cp $rootdir/aboutDialog* im/content/
+cp $rootdir/aboutDialog.dtd im/locales/en-US/chrome/instantbird/aboutDialog.dtd
cd mozilla
if ls -1 $rootdir/*.mozpatch > /dev/null 2>&1
diff --git a/projects/instantbird/config b/projects/instantbird/config
index bd8b4f1..324afd7 100644
--- a/projects/instantbird/config
+++ b/projects/instantbird/config
@@ -94,7 +94,18 @@ input_files:
- filename: branding/name.patch
- filename: branding/instantbird.icns
- filename: branding/credits.patch
+ - filename: branding/jar.patch
- filename: branding/about.png
+ - filename: aboutDialog.xul
+ - filename: aboutDialog.js
+ - filename: aboutDialog-appUpdater.js
+ - filename: aboutDialog-jar.patch
+ - filename: aboutDialog.css
+ - filename: aboutDialog.dtd
+ - filename: about-logo.png
+ - filename: about-logo(a)2x.png
+ - filename: about-wordmark.png
+ - filename: branding-aboutDialog.css
- filename: branding/osx.patch
enable: '[% c("var/osx") %]'
- filename: bug-1218193.patch
1
0

[tor-messenger-build/master] Remove redundant Instantbird about dialog
by arlo@torproject.org 28 Jul '16
by arlo@torproject.org 28 Jul '16
28 Jul '16
commit db5e0c0e6e0a179d4e5a9922e2b1d9d280d91a97
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Thu Jul 14 10:46:39 2016 -0400
Remove redundant Instantbird about dialog
---
projects/instantbird/branding/credits.patch | 201 ----------------------------
projects/instantbird/config | 1 -
2 files changed, 202 deletions(-)
diff --git a/projects/instantbird/branding/credits.patch b/projects/instantbird/branding/credits.patch
deleted file mode 100644
index 1eb297f..0000000
--- a/projects/instantbird/branding/credits.patch
+++ /dev/null
@@ -1,201 +0,0 @@
-diff --git a/im/content/aboutDialog.css b/im/content/aboutDialog.css
---- a/im/content/aboutDialog.css
-+++ b/im/content/aboutDialog.css
-@@ -3,7 +3,7 @@
- }
-
- #modes {
-- min-height: 380px;
-+ min-height: 300px;
- }
-
- #clientBox {
-@@ -18,44 +18,14 @@
- margin: 0px 0px 3px 20px;
- }
-
--#versionField {
-- background-color: #FFFFFF;
-- -moz-appearance: none;
-- border: none;
-- font-weight: bold;
-- color: #909090;
--}
--
--#geckoVersionField,
--#libpurpleVersionField {
-- background-color: #FFFFFF;
-- -moz-appearance: none;
-- border: none;
-- color: #909090;
-- padding-top: 3px !important;
-- padding-left: 10px !important;
--}
--
- #copyright {
- margin: 10px 20px 3px 20px;
- }
-
--#userAgentField {
-- margin: 0px 0px 3px 20px !important;
-- background-color: #FFFFFF;
-- -moz-appearance: none;
-- border: none;
--}
--
- #groove {
- margin-top: 0px;
- }
-
--#creditsIframe {
-- cursor: default;
-- -moz-user-select: none;
--}
--
- button[dlgtype="extra2"] {
- margin-left: 13px;
- }
-diff --git a/im/content/aboutDialog.xul b/im/content/aboutDialog.xul
---- a/im/content/aboutDialog.xul
-+++ b/im/content/aboutDialog.xul
-@@ -14,7 +14,7 @@
- %brandDTD;
- <!ENTITY % aboutDialogDTD SYSTEM "chrome://instantbird/locale/aboutDialog.dtd" >
- %aboutDialogDTD;
--<!ENTITY copyrightYear "2015">
-+<!ENTITY copyrightYear "2016">
- #ifdef XP_MACOSX
- <!ENTITY % instantbirdDTD SYSTEM "chrome://instantbird/locale/instantbird.dtd">
- %instantbirdDTD;
-@@ -24,105 +24,26 @@
- <dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- id="aboutDialog"
- windowtype="Messenger:About"
-- buttons="accept,extra2"
-- onload="onLoad();"
-+ buttons="accept"
- title="&aboutDialog.title;" creditslabel="&credits.label;" creditsaccesskey="&credits.accesskey;"
- aboutlabel="&aboutLink.label;" aboutaccesskey="&aboutLink.accesskey;" versionlabel="&aboutVersion;"
-- style="width: 299px; height: 330px;">
-+ style="width: 310px; height: 330px;">
-
- #ifdef XP_MACOSX
- #include menus.xul.inc
- #endif
-
-- <script type="application/x-javascript">
-- <![CDATA[
-- var gSelectedPage;
--
-- function onLoad() {
-- var xai = Components.classes["@mozilla.org/xre/app-info;1"]
-- .getService(Components.interfaces.nsIXULAppInfo);
--
-- var versionField = document.getElementById("versionField");
-- versionField.value = versionField.value + xai.version
-- + ' (' + xai.appBuildID + ')';
--
-- versionField = document.getElementById("geckoVersionField");
-- versionField.value = versionField.value + xai.platformVersion
-- + ' (' + xai.platformBuildID + ')';
--
-- versionField = document.getElementById("libpurpleVersionField");
-- if ("@instantbird.org/libpurple/core;1" in Components.classes) {
-- var pcs = Components.classes["@instantbird.org/libpurple/core;1"]
-- .getService(Components.interfaces.purpleICoreService);
-- versionField.value = versionField.value + pcs.version;
-- }
-- else {
-- versionField.hidden = true;
-- }
--
-- versionField = document.getElementById("userAgentField");
-- versionField.value = navigator.userAgent;
--
-- var button = document.documentElement.getButton("extra2");
-- button.setAttribute("label", document.documentElement.getAttribute("creditslabel"));
-- button.setAttribute("accesskey", document.documentElement.getAttribute("creditsaccesskey"));
-- gSelectedPage = 0;
-- button.addEventListener("command", switchPage);
-- document.documentElement.getButton("accept").focus();
-- }
--
-- function uninit(aEvent)
-- {
-- if (aEvent.target != document)
-- return;
-- var iframe = document.getElementById("creditsIframe");
-- iframe.setAttribute("src", "");
-- }
--
-- function switchPage(aEvent)
-- {
-- var button = aEvent.target;
-- if (button.localName != "button")
-- return;
--
-- var iframe = document.getElementById("creditsIframe");
-- if (gSelectedPage == 0) {
-- iframe.setAttribute("src", "chrome://instantbird/content/credits.xhtml");
-- button.setAttribute("label", document.documentElement.getAttribute("aboutlabel"));
-- button.setAttribute("accesskey", document.documentElement.getAttribute("aboutaccesskey"));
-- gSelectedPage = 1;
-- }
-- else {
-- iframe.setAttribute("src", "");
-- button.setAttribute("label", document.documentElement.getAttribute("creditslabel"));
-- button.setAttribute("accesskey", document.documentElement.getAttribute("creditsaccesskey"));
-- gSelectedPage = 0;
-- }
-- var modes = document.getElementById("modes");
-- modes.setAttribute("selectedIndex", gSelectedPage);
-- }
-- ]]>
-- </script>
--
- <deck id="modes" flex="1">
- <vbox flex="1" id="clientBox">
-- <vbox id="versionWrapper" flex="1">
-- <textbox id="versionField" readonly="true" class="plain" tabindex="2"
-- value="&aboutVersion; "/>
-- <textbox id="geckoVersionField" readonly="true" class="plain"
-- tabindex="3" value="&geckoVersion; "/>
-- <textbox id="libpurpleVersionField" readonly="true" class="plain"
-- tabindex="4" value="&libpurpleVersion; "/>
-- </vbox>
-+ <vbox id="versionWrapper" align="center" flex="1">
-+ <separator/>
-+ <label id="tmLabel" value="&tmText;" />
-+ <label id="imLabel" value="&imText;" />
-+ </vbox>
- <description id="copyright" flex="1">©rightText2;</description>
- <separator/>
-- <textbox id="userAgentField" readonly="true" class="plain"
-- tabindex="5" multiline="true"/>
- </vbox>
-
-- <vbox flex="1" id="creditsBox">
-- <iframe id="creditsIframe" flex="1"/>
-- </vbox>
- </deck>
-
- <separator class="groove" id="groove"/>
-diff --git a/im/locales/en-US/chrome/instantbird/aboutDialog.dtd b/im/locales/en-US/chrome/instantbird/aboutDialog.dtd
---- a/im/locales/en-US/chrome/instantbird/aboutDialog.dtd
-+++ b/im/locales/en-US/chrome/instantbird/aboutDialog.dtd
-@@ -1,4 +1,4 @@
--<!ENTITY aboutDialog.title "About &brandFullName;">
-+<!ENTITY aboutDialog.title "About &brandShortName;">
- <!ENTITY credits.label "Credits">
- <!ENTITY credits.accesskey "C">
- <!ENTITY aboutLink.label "< About &brandShortName;">
-@@ -6,5 +6,8 @@
- <!ENTITY aboutVersion "version">
- <!ENTITY geckoVersion "Gecko">
- <!ENTITY libpurpleVersion "libpurple">
-+<!ENTITY ibVersion "Nightly">
-+<!ENTITY tmText "Version &tmVersion;">
-+<!ENTITY imText "(Based on Instantbird IM &ibVersion;)">
- <!-- Use the ©rightYear; entity to place the current year. -->
--<!ENTITY copyrightText2 "©2007-©rightYear; Contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU GPL license version 2.0 or later.">
-+<!ENTITY copyrightText2 "©©rightYear; The Tor Project, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU GPL license version 2.0 or later.">
diff --git a/projects/instantbird/config b/projects/instantbird/config
index b3623d6..27f9d6f 100644
--- a/projects/instantbird/config
+++ b/projects/instantbird/config
@@ -93,7 +93,6 @@ input_files:
- filename: branding/instantbird.ico
- filename: branding/name.patch
- filename: branding/instantbird.icns
- - filename: branding/credits.patch
- filename: branding/jar.patch
- filename: branding/about.png
- filename: aboutDialog.xul
1
0

[tor-messenger-build/master] Use Debian 7.11 image for Linux builds
by arlo@torproject.org 28 Jul '16
by arlo@torproject.org 28 Jul '16
28 Jul '16
commit 9979e309fa0a311602826a763e81af441ce05cbf
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Wed Jul 13 15:42:17 2016 -0400
Use Debian 7.11 image for Linux builds
---
projects/instantbird/config | 4 ++--
rbm.conf | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/projects/instantbird/config b/projects/instantbird/config
index 324afd7..b3623d6 100644
--- a/projects/instantbird/config
+++ b/projects/instantbird/config
@@ -36,7 +36,7 @@ targets:
linux-x86_64:
var:
arch_deps:
- - yasm-1
+ - yasm
linux-i686:
var:
arch_deps:
@@ -44,7 +44,7 @@ targets:
- ia32-libs
- lib32z1-dev
- lib32asound2-dev
- - yasm-1
+ - yasm
osx-x86_64:
var:
arch_deps:
diff --git a/rbm.conf b/rbm.conf
index 7d35cc2..c3b3a3b 100644
--- a/rbm.conf
+++ b/rbm.conf
@@ -27,14 +27,14 @@ targets:
noint:
debug: 0
linux-x86_64:
- distribution: Ubuntu-10.04
+ distribution: Debian-7.11
arch: x86_64
var:
linux: 1
osname: linux-x86_64
compiler: gcc
linux-i686:
- distribution: Ubuntu-10.04
+ distribution: Debian-7.11
arch: i686
var:
linux: 1
1
0

28 Jul '16
commit fca081302c464455f56315977e93af4e8310f560
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Wed Jul 13 10:51:33 2016 -0400
Update vendor name (Tor Project)
---
projects/instantbird/branding/name.patch | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/projects/instantbird/branding/name.patch b/projects/instantbird/branding/name.patch
index b183212..57d3d94 100644
--- a/projects/instantbird/branding/name.patch
+++ b/projects/instantbird/branding/name.patch
@@ -11,7 +11,7 @@ index e5b5348..276722b 100755
-!define URLInfoAbout "http://www.instantbird.com/"
-!define URLUpdateInfo "http://www.instantbird.com/"
+!define BrandFullNameInternal "Tor Messenger"
-+!define CompanyName "Tor Messenger"
++!define CompanyName "Tor Project"
+!define URLInfoAbout "https://www.torproject.org"
+!define URLUpdateInfo "https://www.torproject.org"
@@ -29,7 +29,7 @@ index c569ebb..2d6a5d8 100644
+<!ENTITY brandFullName "Tor Messenger - Beta">
<!ENTITY brandMotto "'Cause geeks can also do magic!">
-<!ENTITY vendorShortName "Instantbird">
-+<!ENTITY vendorShortName "Tor Messenger">
++<!ENTITY vendorShortName "Tor Project">
diff --git a/im/branding/messenger/locales/en-US/brand.properties b/im/branding/messenger/locales/en-US/brand.properties
index f949ced..93528a3 100644
--- a/im/branding/messenger/locales/en-US/brand.properties
@@ -43,4 +43,4 @@ index f949ced..93528a3 100644
-vendorShortName=Instantbird
+brandShortName=Tor Messenger
+brandFullName=Tor Messenger - Beta
-+vendorShortName=Tor Messenger
++vendorShortName=Tor Project
1
0

[tor-messenger-build/master] Remove obsolete patching of torrc-defaults
by arlo@torproject.org 28 Jul '16
by arlo@torproject.org 28 Jul '16
28 Jul '16
commit b23115185109cf06cfe6a107c928de4e1d8a9533
Author: Sukhbir Singh <sukhbir(a)torproject.org>
Date: Mon Jul 11 12:19:36 2016 -0400
Remove obsolete patching of torrc-defaults
---
projects/tor-messenger/build | 4 ----
1 file changed, 4 deletions(-)
diff --git a/projects/tor-messenger/build b/projects/tor-messenger/build
index f50c490..d69c983 100755
--- a/projects/tor-messenger/build
+++ b/projects/tor-messenger/build
@@ -73,14 +73,10 @@ sed -i 's/^ControlPort .*/ControlPort [% c("var/tor_control_port") %]/' tor-brow
[% IF c("var/windows") -%]
# use meek in standalone mode: https://lists.torproject.org/pipermail/tor-dev/2015-November/009887.html
sed -i 's/\(ClientTransportPlugin meek exec\) [^ ]\+ [^ ]\+ -- /\1 /' tor-browser_en-US/Browser/TorBrowser/Data/Tor/torrc-defaults
-sed -i 's|TorBrowser\\Tor\\PluggableTransports|TorBrowser\\Tor\\PluggableTransports|g' \
- tor-browser_en-US/Browser/TorBrowser/Data/Tor/torrc-defaults
rm -f tor-browser_en-US/Browser/TorBrowser/Tor/PluggableTransports/meek-client-torbrowser.exe
[% ELSE -%]
# use meek in standalone mode: https://lists.torproject.org/pipermail/tor-dev/2015-November/009887.html
sed -i 's/\(ClientTransportPlugin meek exec\) [^ ]\+ -- /\1 /' tor-browser_en-US/Browser/TorBrowser/Data/Tor/torrc-defaults
-sed -i 's|TorBrowser/Tor/PluggableTransports|TorBrowser/Tor/PluggableTransports|g' \
- tor-browser_en-US/Browser/TorBrowser/Data/Tor/torrc-defaults
rm -f tor-browser_en-US/Browser/TorBrowser/Tor/PluggableTransports/meek-client-torbrowser
[% END -%]
1
0