Bug 741336 - Provide UI to easily clear cookies from the menus. r=mbanner, ui-r=bwinton
authorAndrew Johnston <awjohnston1@gmail.com>
Mon, 23 Jul 2012 19:24:15 -0400
changeset 11828 76efc33d143a711a6a8b4000d2dcf08f4e638803
parent 11827 3b29e269e62efe27e66cbf5cd5502c06769edae6
child 11829 f91c69072cf6e5f395ccf7916629f6d50ade9cd2
push id681
push userbugzilla@standard8.plus.com
push dateMon, 27 Aug 2012 20:55:32 +0000
treeherdercomm-aurora@55ece6cec5cd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmbanner, bwinton
bugs741336
Bug 741336 - Provide UI to easily clear cookies from the menus. r=mbanner, ui-r=bwinton
mail/app/profile/all-thunderbird.js
mail/base/content/mailCore.js
mail/base/content/mailWindowOverlay.xul
mail/base/content/sanitize.js
mail/base/content/sanitize.xul
mail/base/content/sanitizeDialog.css
mail/base/content/sanitizeDialog.js
mail/base/jar.mn
mail/components/Makefile.in
mail/components/mailGlue.js
mail/components/nsIMailGlue.idl
mail/locales/en-US/chrome/messenger/messenger.dtd
mail/locales/en-US/chrome/messenger/messenger.properties
mail/locales/en-US/chrome/messenger/sanitize.dtd
mail/locales/jar.mn
mail/themes/gnomestripe/jar.mn
mail/themes/gnomestripe/sanitizeDialog.css
mail/themes/pinstripe/jar.mn
mail/themes/pinstripe/places/expander-closed-active.png
mail/themes/pinstripe/places/expander-closed.png
mail/themes/pinstripe/places/expander-open-active.png
mail/themes/pinstripe/places/expander-open.png
mail/themes/pinstripe/sanitizeDialog.css
mail/themes/qute/jar.mn
mail/themes/qute/sanitizeDialog.css
--- a/mail/app/profile/all-thunderbird.js
+++ b/mail/app/profile/all-thunderbird.js
@@ -758,10 +758,22 @@ pref("mail.chat.play_notification_sound"
 // Send typing notification in private conversations
 pref("purple.conversations.im.send_typing", true);
 
 // BigFiles
 pref("mail.cloud_files.enabled", true);
 pref("mail.cloud_files.inserted_urls.footer.link", "http://www.getthunderbird.com");
 pref("mail.cloud_files.learn_more_url", "https://support.mozillamessaging.com/kb/filelink-large-attachments");
 
+// Sanitize dialog window
+pref("privacy.cpd.cookies", true);
+pref("privacy.cpd.cache", true);
+
+// What default should we use for the time span in the sanitizer:
+// 0 - Clear everything
+// 1 - Last Hour
+// 2 - Last 2 Hours
+// 3 - Last 4 Hours
+// 4 - Today
+pref("privacy.sanitize.timeSpan", 1);
+
 // PgpMime Proxy
 pref("mail.pgpmime.addon_url", "https://addons.mozilla.org/thunderbird/addon/enigmail/");
--- a/mail/base/content/mailCore.js
+++ b/mail/base/content/mailCore.js
@@ -345,16 +345,23 @@ function showChatTab()
 }
 
 function toImport()
 {
   window.openDialog("chrome://messenger/content/importDialog.xul", "importDialog",
                     "chrome, modal, titlebar, centerscreen");
 }
 
+function toSanitize()
+{
+   Components.classes["@mozilla.org/mail/mailglue;1"]
+             .getService(Components.interfaces.nsIMailGlue)
+             .sanitize(window);
+}
+
 /**
  * Opens the Preferences (Options) dialog.
  *
  * @param aPaneID     ID of prefpane to select automatically.
  * @param aTabID      ID of tab to select on the prefpane.
  * @param aOtherArgs  other prefpane specific arguments
  */
 function openOptionsDialog(aPaneID, aTabID, aOtherArgs)
--- a/mail/base/content/mailWindowOverlay.xul
+++ b/mail/base/content/mailWindowOverlay.xul
@@ -1690,16 +1690,20 @@
             label="&deleteJunk.label;"
             accesskey="&deleteJunk.accesskey;"
             command="cmd_deleteJunk"/>
         <menuseparator id="tasksMenuAfterDeleteSeparator"/>
         <menuitem id="menu_import" label="&importCmd.label;"
                   accesskey="&importCmd.accesskey;"
                   oncommand="toImport();"/>
         <menuitem id="javascriptConsole" label="&errorConsoleCmd.label;" accesskey="&errorConsoleCmd.accesskey;" key="key_errorConsole" oncommand="toJavaScriptConsole();"/>
+        <menuitem id="sanitizeHistory"
+                  label="&clearRecentHistory.label;"                       
+                  accesskey="&clearRecentHistory.accesskey;"
+                  oncommand="toSanitize();"/>
 #ifndef XP_UNIX
         <menuseparator id="prefSep"/>
         <menuitem id="menu_accountmgr" label="&accountManagerCmd.label;" accesskey="&accountManagerCmd.accesskey;" oncommand="MsgAccountManager(null);"/>
         <menuitem id="menu_preferences" oncommand="openOptionsDialog()"/>
 #else
 #ifdef XP_MACOSX
         <menuseparator id="prefSep"/>
         <menuitem id="menu_accountmgr" label="&accountManagerCmd.label;" accesskey="&accountManagerCmd.accesskey;" oncommand="MsgAccountManager(null);"/>
new file mode 100644
--- /dev/null
+++ b/mail/base/content/sanitize.js
@@ -0,0 +1,250 @@
+/* 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/. */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+var Application = Components.classes["@mozilla.org/steel/application;1"]
+                            .getService(Components.interfaces.steelIApplication);
+
+function Sanitizer() {}
+Sanitizer.prototype = {
+  // warning to the caller: this one may raise an exception (e.g. bug #265028)
+  clearItem: function (aItemName)
+  {
+    if (this.items[aItemName].canClear)
+      this.items[aItemName].clear();
+  },
+
+  canClearItem: function (aItemName)
+  {
+    return this.items[aItemName].canClear;
+  },
+  
+  prefDomain: "",
+  
+  getNameFromPreference: function (aPreferenceName)
+  {
+    return aPreferenceName.substr(this.prefDomain.length);
+  },
+  
+  /**
+   * Deletes privacy sensitive data in a batch, according to user preferences
+   *
+   * @returns  null if everything's fine;  an object in the form
+   *           { itemName: error, ... } on (partial) failure
+   */
+  sanitize: function ()
+  {
+    var branch = Services.prefs.getBranch(this.prefDomain);
+    var errors = null;
+
+    // Cache the range of times to clear
+    if (this.ignoreTimespan)
+      var range = null;  // If we ignore timespan, clear everything
+    else
+      range = this.range || Sanitizer.getClearRange();
+      
+    for (var itemName in this.items) {
+      var item = this.items[itemName];
+      item.range = range;
+      if ("clear" in item && item.canClear && branch.getBoolPref(itemName)) {
+        // Some of these clear() may raise exceptions (see bug #265028)
+        // to sanitize as much as possible, we catch and store them, 
+        // rather than fail fast.
+        // Callers should check returned errors and give user feedback
+        // about items that could not be sanitized
+        try {
+          item.clear();
+        } catch(er) {
+          if (!errors) 
+            errors = {};
+          errors[itemName] = er;
+          dump("Error sanitizing " + itemName + ": " + er + "\n");
+        }
+      }
+    }
+    return errors;
+  },
+  
+  // Time span only makes sense in certain cases.  Consumers who want
+  // to only clear some private data can opt in by setting this to false,
+  // and can optionally specify a specific range.  If timespan is not ignored,
+  // and range is not set, sanitize() will use the value of the timespan
+  // pref to determine a range
+  ignoreTimespan : true,
+  range : null,
+  
+  items: {
+    cache: {
+      clear: function ()
+      {
+        try {
+          // Cache doesn't consult timespan, nor does it have the
+          // facility for timespan-based eviction.  Wipe it.
+          Services.cache.evictEntries(Ci.nsICache.STORE_ANYWHERE);
+        } catch(er) {}
+
+      },
+      
+      get canClear()
+      {
+        return true;
+      }
+    },
+    
+    cookies: {
+      clear: function ()
+      {
+        if (this.range) {
+          // Iterate through the cookies and delete any created after our cutoff.
+          var cookiesEnum = Services.cookies.enumerator;
+          while (cookiesEnum.hasMoreElements()) {
+            var cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2);
+            
+            if (cookie.creationTime > this.range[0])
+              // This cookie was created after our cutoff, clear it
+              Services.cookies.remove(cookie.host, cookie.name, cookie.path, false);
+          }
+        }
+        else {
+          // Remove everything
+          Services.cookies.removeAll();
+        }
+
+        // Clear plugin data.
+        const phInterface = Ci.nsIPluginHost;
+        const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
+        let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface);
+
+        // Determine age range in seconds. (-1 means clear all.) We don't know
+        // that this.range[1] is actually now, so we compute age range based
+        // on the lower bound. If this.range results in a negative age, do
+        // nothing.
+        let age = this.range ? (Date.now() / 1000 - this.range[0] / 1000000)
+                             : -1;
+        if (!this.range || age >= 0) {
+          let tags = ph.getPluginTags();
+          for (let i = 0; i < tags.length; i++) {
+            try {
+              ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, age);
+            } catch (e) {
+              // If the plugin doesn't support clearing by age, clear everything.
+              if (e.result == Components.results.
+                    NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) {
+                try {
+                  ph.clearSiteData(tags[i], null, FLAG_CLEAR_ALL, -1);
+                } catch (e) {
+                  // Ignore errors from the plugin
+                }
+              }
+            }
+          }
+        }
+
+        // clear any network geolocation provider sessions
+        try {
+            var branch = Services.prefs.getBranch("geo.wifi.access_token.");
+            branch.deleteBranch("");
+        } catch (e) {}
+
+      },
+
+      get canClear()
+      {
+        return true;
+      }
+    },
+  }
+};
+
+// "Static" members
+Sanitizer.prefDomain          = "privacy.sanitize.";
+Sanitizer.prefShutdown        = "sanitizeOnShutdown";
+Sanitizer.prefDidShutdown     = "didShutdownSanitize";
+
+// Time span constants corresponding to values of the privacy.sanitize.timeSpan
+// pref.  Used to determine how much history to clear, for various items
+Sanitizer.TIMESPAN_EVERYTHING = 0;
+Sanitizer.TIMESPAN_HOUR       = 1;
+Sanitizer.TIMESPAN_2HOURS     = 2;
+Sanitizer.TIMESPAN_4HOURS     = 3;
+Sanitizer.TIMESPAN_TODAY      = 4;
+
+// Return a 2 element array representing the start and end times,
+// in the uSec-since-epoch format that PRTime likes.  If we should
+// clear everything, return null.  Use ts if it is defined; otherwise
+// use the timeSpan pref.
+Sanitizer.getClearRange = function (ts) {
+  if (ts === undefined)
+    ts = Sanitizer.prefs.getIntPref("timeSpan");
+  if (ts === Sanitizer.TIMESPAN_EVERYTHING)
+    return null;
+  
+  // PRTime is microseconds while JS time is milliseconds
+  var endDate = Date.now() * 1000;
+  switch (ts) {
+    case Sanitizer.TIMESPAN_HOUR :
+      var startDate = endDate - 3600000000; // 1*60*60*1000000
+      break;
+    case Sanitizer.TIMESPAN_2HOURS :
+      startDate = endDate - 7200000000; // 2*60*60*1000000
+      break;
+    case Sanitizer.TIMESPAN_4HOURS :
+      startDate = endDate - 14400000000; // 4*60*60*1000000
+      break;
+    case Sanitizer.TIMESPAN_TODAY :
+      var d = new Date();  // Start with today
+      d.setHours(0);      // zero us back to midnight...
+      d.setMinutes(0);
+      d.setSeconds(0);
+      startDate = d.valueOf() * 1000; // convert to epoch usec
+      break;
+    default:
+      throw "Invalid time span for clear private data: " + ts;
+  }
+  return [startDate, endDate];
+};
+
+Sanitizer._prefs = null;
+Sanitizer.__defineGetter__("prefs", function() 
+{
+  return Sanitizer._prefs ? Sanitizer._prefs
+    : Sanitizer._prefs = Components.classes["@mozilla.org/preferences-service;1"]
+                         .getService(Components.interfaces.nsIPrefService)
+                         .getBranch(Sanitizer.prefDomain);
+});
+
+// Shows sanitization UI
+Sanitizer.showUI = function(aParentWindow) 
+{
+Services.ww.openWindow(Application.platformIsMac ? null : aParentWindow,
+"chrome://messenger/content/sanitize.xul",
+                "Sanitize",
+                "chrome,titlebar,dialog,centerscreen,modal",
+                null);                
+};
+
+/** 
+ * Deletes privacy sensitive data in a batch, optionally showing the 
+ * sanitize UI, according to user preferences
+ */
+Sanitizer.sanitize = function(aParentWindow) 
+{
+  Sanitizer.showUI(aParentWindow);
+};
+
+// this is called on startup and shutdown, to perform pending sanitizations
+Sanitizer._checkAndSanitize = function() 
+{
+  const prefs = Sanitizer.prefs;
+  if (prefs.getBoolPref(Sanitizer.prefShutdown) && 
+      !prefs.prefHasUserValue(Sanitizer.prefDidShutdown)) {
+    // this is a shutdown or a startup after an unclean exit
+    var s = new Sanitizer();
+    s.prefDomain = "privacy.clearOnShutdown.";
+    s.sanitize() || // sanitize() returns null on full success
+      prefs.setBoolPref(Sanitizer.prefDidShutdown, true);
+  }
+};
+
+
new file mode 100644
--- /dev/null
+++ b/mail/base/content/sanitize.xul
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+
+<!-- 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/"?>
+<?xml-stylesheet href="chrome://messenger/skin/sanitizeDialog.css"?>
+ 
+<?xml-stylesheet href="chrome://messenger/content/sanitizeDialog.css"?>
+
+<!DOCTYPE prefwindow [
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+  <!ENTITY % sanitizeDTD SYSTEM "chrome://messenger/locale/sanitize.dtd">
+  %brandDTD;
+  %sanitizeDTD;
+]>
+
+<prefwindow id="SanitizeDialog" type="child"
+            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+            dlgbuttons="accept,cancel"
+            title="&sanitizeDialog2.title;"
+            noneverythingtitle="&sanitizeDialog2.title;"
+            style="width: &dialog.width;"
+            ondialogaccept="gSanitizePromptDialog.sanitize();">
+
+  <prefpane id="SanitizeDialogPane" onpaneload="gSanitizePromptDialog.init();">
+	<stringbundle id="bundleBrowser"
+            src="chrome://messenger/locale/messenger.properties"/>
+
+    <script type="application/javascript"
+            src="chrome://messenger/content/sanitize.js"/>
+
+    <script type="application/javascript"
+            src="chrome://messenger/content/sanitizeDialog.js"/>
+
+    <preferences id="sanitizePreferences">
+      <preference id="privacy.cpd.cookies" name="privacy.cpd.cookies" type="bool"/>
+      <preference id="privacy.cpd.cache"   name="privacy.cpd.cache"   type="bool"/>
+    </preferences>
+    
+    <preferences id="nonItemPreferences">
+      <preference id="privacy.sanitize.timeSpan"
+                  name="privacy.sanitize.timeSpan"
+                  type="int"/>
+    </preferences>
+
+    <hbox id="SanitizeDurationBox" align="center">
+      <label value="&clearTimeDuration.label;"
+             accesskey="&clearTimeDuration.accesskey;"
+             control="sanitizeDurationChoice"
+             id="sanitizeDurationLabel"/>
+      <menulist id="sanitizeDurationChoice"
+                preference="privacy.sanitize.timeSpan"
+                onselect="gSanitizePromptDialog.selectByTimespan();"
+                flex="1">
+        <menupopup id="sanitizeDurationPopup">
+          <menuitem label="&clearTimeDuration.lastHour;" value="1"/>
+          <menuitem label="&clearTimeDuration.last2Hours;" value="2"/>
+          <menuitem label="&clearTimeDuration.last4Hours;" value="3"/>
+          <menuitem label="&clearTimeDuration.today;" value="4"/>
+          <menuseparator/>
+          <menuitem label="&clearTimeDuration.everything;" value="0"/>
+        </menupopup>
+      </menulist>
+      <label id="sanitizeDurationSuffixLabel"
+             value="&clearTimeDuration.suffix;"/>
+    </hbox>
+
+    <separator class="thin"/>
+
+      <vbox id="sanitizeEverythingWarningBox">
+        <spacer flex="1"/>
+        <hbox align="center">
+          <image id="sanitizeEverythingWarningIcon"/>
+          <vbox id="sanitizeEverythingWarningDescBox" flex="1">
+            <description id="sanitizeEverythingWarning"/>
+            <description id="sanitizeEverythingUndoWarning">&sanitizeEverythingUndoWarning;</description>
+          </vbox>
+        </hbox>
+        <spacer flex="1"/>
+      </vbox>
+
+    <separator class="thin"/>
+
+    <hbox id="detailsExpanderWrapper" align="center">
+      <button type="image"
+              id="detailsExpander"
+              class="expander-down"
+              persist="class"
+              oncommand="gSanitizePromptDialog.toggleItemList();"/>
+      <label id="detailsExpanderLabel"
+             value="&detailsProgressiveDisclosure.label;"
+             accesskey="&detailsProgressiveDisclosure.accesskey;"
+             control="detailsExpander"/>
+    </hbox>
+    <listbox id="itemList" rows="2" collapsed="true" persist="collapsed">
+      <listitem label="&itemCookies.label;"
+                type="checkbox"
+                accesskey="&itemCookies.accesskey;"
+                preference="privacy.cpd.cookies"
+                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+      <listitem label="&itemCache.label;"
+                type="checkbox"
+                accesskey="&itemCache.accesskey;"
+                preference="privacy.cpd.cache"
+                onsyncfrompreference="return gSanitizePromptDialog.onReadGeneric();"/>
+    </listbox>
+
+  </prefpane>
+</prefwindow>
new file mode 100644
--- /dev/null
+++ b/mail/base/content/sanitizeDialog.css
@@ -0,0 +1,23 @@
+/* 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/. */
+
+/* Places tree */
+
+#placesTreechildren {
+  -moz-user-focus: normal;
+}
+
+#placesTreechildren::-moz-tree-cell(grippyRow),
+#placesTreechildren::-moz-tree-cell-text(grippyRow),
+#placesTreechildren::-moz-tree-image(grippyRow) {
+  cursor: -moz-grab;
+}
+
+
+/* Sanitize everything warnings */
+
+#sanitizeEverythingWarning,
+#sanitizeEverythingUndoWarning {
+  white-space: pre-wrap;
+}
new file mode 100644
--- /dev/null
+++ b/mail/base/content/sanitizeDialog.js
@@ -0,0 +1,251 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+var gSanitizePromptDialog = {
+
+  get bundleBrowser()
+  {
+    if (!this._bundleBrowser)
+      this._bundleBrowser = document.getElementById("bundleBrowser");
+    return this._bundleBrowser;
+  },
+
+  get selectedTimespan()
+  {
+    var durList = document.getElementById("sanitizeDurationChoice");
+    return parseInt(durList.value);
+  },
+
+  get sanitizePreferences()
+  {
+    if (!this._sanitizePreferences) {
+      this._sanitizePreferences =
+        document.getElementById("sanitizePreferences");
+    }
+    return this._sanitizePreferences;
+  },
+
+  get warningBox()
+  {
+    return document.getElementById("sanitizeEverythingWarningBox");
+  },
+
+  init: function ()
+  {
+    // This is used by selectByTimespan() to determine if the window has loaded.
+    this._inited = true;
+
+    var s = new Sanitizer();
+    s.prefDomain = "privacy.cpd.";
+
+    let sanitizeItemList = document.querySelectorAll("#itemList > [preference]");
+    for (let i = 0; i < sanitizeItemList.length; i++) {
+      let prefItem = sanitizeItemList[i];
+      let name = s.getNameFromPreference(prefItem.getAttribute("preference"));
+      if (!s.canClearItem(name)) {
+        prefItem.preference = null;
+        prefItem.checked = false;
+        prefItem.disabled = true;
+      }
+    }
+
+    document.documentElement.getButton("accept").label =
+      this.bundleBrowser.getString("sanitizeButtonOK");
+
+    if (this.selectedTimespan === Sanitizer.TIMESPAN_EVERYTHING) {
+      this.prepareWarning();
+      this.warningBox.hidden = false;
+      document.title =
+        this.bundleBrowser.getString("sanitizeDialog2.everything.title");
+    }
+    else
+      this.warningBox.hidden = true;
+  },
+
+  selectByTimespan: function ()
+  {
+    // This method is the onselect handler for the duration dropdown.  As a
+    // result it's called a couple of times before onload calls init().
+    if (!this._inited)
+      return;
+
+    var warningBox = this.warningBox;
+
+    // If clearing everything
+    if (this.selectedTimespan === Sanitizer.TIMESPAN_EVERYTHING) {
+      this.prepareWarning();
+      if (warningBox.hidden) {
+        warningBox.hidden = false;
+        window.resizeBy(0, warningBox.boxObject.height);
+      }
+      window.document.title =
+        this.bundleBrowser.getString("sanitizeDialog2.everything.title");
+      return;
+    }
+
+    // If clearing a specific time range
+    if (!warningBox.hidden) {
+      window.resizeBy(0, -warningBox.boxObject.height);
+      warningBox.hidden = true;
+    }
+    window.document.title =
+      window.document.documentElement.getAttribute("noneverythingtitle");
+  },
+
+  sanitize: function ()
+  {
+    // Update pref values before handing off to the sanitizer (bug 453440)
+    this.updatePrefs();
+    var s = new Sanitizer();
+    s.prefDomain = "privacy.cpd.";
+
+    s.range = Sanitizer.getClearRange(this.selectedTimespan);
+    s.ignoreTimespan = !s.range;
+
+    try {
+      s.sanitize();
+    } catch (er) {
+      Components.utils.reportError("Exception during sanitize: " + er);
+    }
+    return true;
+  },
+
+  /**
+   * If the panel that displays a warning when the duration is "Everything" is
+   * not set up, sets it up.  Otherwise does nothing.
+   *
+   * @param aDontShowItemList Whether only the warning message should be updated.
+   *                          True means the item list visibility status should not
+   *                          be changed.
+   */
+  prepareWarning: function (aDontShowItemList) {
+    // If the date and time-aware locale warning string is ever used again,
+    // initialize it here.  Currently we use the no-visits warning string,
+    // which does not include date and time.  See bug 480169 comment 48.
+
+    var warningStringID;
+    if (this.hasNonSelectedItems()) {
+      warningStringID = "sanitizeSelectedWarning";
+      if (!aDontShowItemList)
+        this.showItemList();
+    }
+    else {
+      warningStringID = "sanitizeEverythingWarning2";
+    }
+
+    var warningDesc = document.getElementById("sanitizeEverythingWarning");
+    warningDesc.textContent =
+      this.bundleBrowser.getString(warningStringID);
+  },
+
+  /**
+   * Called when the value of a preference element is synced from the actual
+   * pref.  Enables or disables the OK button appropriately.
+   */
+  onReadGeneric: function ()
+  {
+    var found = false;
+
+    // Find any other pref that's checked and enabled.
+    var i = 0;
+    while (!found && i < this.sanitizePreferences.childNodes.length) {
+      var preference = this.sanitizePreferences.childNodes[i];
+
+      found = !!preference.value &&
+              !preference.disabled;
+      i++;
+    }
+
+    try {
+      document.documentElement.getButton("accept").disabled = !found;
+    }
+    catch (e) { }
+
+    // Update the warning prompt if needed
+    this.prepareWarning(true);
+
+    return undefined;
+  },
+
+  /**
+   * Sanitizer.prototype.sanitize() requires the prefs to be up-to-date.
+   * Because the type of this prefwindow is "child" -- and that's needed because
+   * without it the dialog has no OK and Cancel buttons -- the prefs are not
+   * updated on dialogaccept on platforms that don't support instant-apply
+   * (i.e., Windows).  We must therefore manually set the prefs from their
+   * corresponding preference elements.
+   */
+  updatePrefs : function ()
+  {
+    var tsPref = document.getElementById("privacy.sanitize.timeSpan");
+    Sanitizer.prefs.setIntPref("timeSpan", this.selectedTimespan);
+
+    // Now manually set the prefs from their corresponding preference
+    // elements.
+    var prefs = this.sanitizePreferences.rootBranch;
+    for (let i = 0; i < this.sanitizePreferences.childNodes.length; ++i) {
+      var p = this.sanitizePreferences.childNodes[i];
+      prefs.setBoolPref(p.name, p.value);
+    }
+  },
+
+  /**
+   * Check if all of the history items have been selected like the default status.
+   */
+  hasNonSelectedItems: function () {
+    let checkboxes = document.querySelectorAll("#itemList > [preference]");
+    for (let i = 0; i < checkboxes.length; ++i) {
+      let pref = document.getElementById(checkboxes[i].getAttribute("preference"));
+      if (!pref.value)
+        return true;
+    }
+    return false;
+  },
+
+  /**
+   * Show the history items list.
+   */
+  showItemList: function () {
+    var itemList = document.getElementById("itemList");
+    var expanderButton = document.getElementById("detailsExpander");
+
+    if (itemList.collapsed) {
+      expanderButton.className = "expander-up";
+      itemList.setAttribute("collapsed", "false");
+      if (document.documentElement.boxObject.height)
+        window.resizeBy(0, itemList.boxObject.height);
+    }
+  },
+
+  /**
+   * Hide the history items list.
+   */
+  hideItemList: function () {
+    var itemList = document.getElementById("itemList");
+    var expanderButton = document.getElementById("detailsExpander");
+
+    if (!itemList.collapsed) {
+      expanderButton.className = "expander-down";
+      window.resizeBy(0, -itemList.boxObject.height);
+      itemList.setAttribute("collapsed", "true");
+    }
+  },
+
+  /**
+   * Called by the item list expander button to toggle the list's visibility.
+   */
+  toggleItemList: function ()
+  {
+    var itemList = document.getElementById("itemList");
+
+    if (itemList.collapsed)
+      this.showItemList();
+    else
+      this.hideItemList();
+  }
+};
\ No newline at end of file
--- a/mail/base/jar.mn
+++ b/mail/base/jar.mn
@@ -102,16 +102,20 @@ messenger.jar:
     content/messenger/quickFilterBar.xul            (content/quickFilterBar.xul)
     content/messenger/quickFilterBar.js             (content/quickFilterBar.js)
     content/messenger/quickFilterBar.css            (content/quickFilterBar.css)
     content/messenger/downloadsOverlay.xul          (content/downloadsOverlay.xul)
     content/messenger/browserRequest.js             (content/browserRequest.js)
     content/messenger/browserRequest.xul            (content/browserRequest.xul)
 *   content/messenger/safeMode.xul                  (content/safeMode.xul)
     content/messenger/safeMode.js                   (content/safeMode.js)
+	content/messenger/sanitize.xul					(content/sanitize.xul)
+	content/messenger/sanitize.js					(content/sanitize.js)
+	content/messenger/sanitizeDialog.css			(content/sanitizeDialog.css)
+	content/messenger/sanitizeDialog.js				(content/sanitizeDialog.js)
 # the following files are mail-specific overrides
 *+  content/messenger/license.html                  (/mozilla/toolkit/content/license.html)
 % override chrome://global/content/license.html chrome://messenger/content/license.html
 
 comm.jar:
 % content communicator %content/communicator/
    content/communicator/contentAreaClick.js         (content/contentAreaClick.js)
 *  content/communicator/utilityOverlay.xul          (content/utilityOverlay.xul)
--- a/mail/components/Makefile.in
+++ b/mail/components/Makefile.in
@@ -4,16 +4,23 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DEPTH   = ../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH   = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
+
+MODULE = mailcomps
+XPIDL_MODULE = mailcompsbase
+
+XPIDLSRCS = \
+      nsIMailGlue.idl \
+      $(NULL)
 
 # Only Mac and Windows have search integration components, but we include at
 # least one module from search/ on all platforms
 DIRS    = compose cloudfile preferences addrbook migration activity search about-support wintaskbar newmailaccount im
 
 ifneq (,$(filter windows gtk2 cocoa, $(MOZ_WIDGET_TOOLKIT)))
 DIRS += shell
 endif
--- a/mail/components/mailGlue.js
+++ b/mail/components/mailGlue.js
@@ -15,16 +15,23 @@ Cu.import("resource:///modules/mailMigra
 
 /**
  * Glue code that should be executed before any windows are opened. Any
  * window-independent helper methods (a la nsBrowserGlue.js) should go in
  * MailUtils.js instead.
  */
 
 function MailGlue() {
+	XPCOMUtils.defineLazyGetter(this, "_sanitizer",
+		function() {
+		let sanitizerScope = {};
+		Services.scriptloader.loadSubScript("chrome://messenger/content/sanitize.js", sanitizerScope);
+		return sanitizerScope.Sanitizer;
+	});
+
   this._init();
 }
 
 MailGlue.prototype = {
   // init (called at app startup)
   _init: function MailGlue__init() {
     Services.obs.addObserver(this, "xpcom-shutdown", false);
     Services.obs.addObserver(this, "final-ui-startup", false);
@@ -48,16 +55,21 @@ MailGlue.prototype = {
       this._onProfileStartup();
       break;
     case "mail-startup-done":
       this._onMailStartupDone();
       break;
     }
   },
 
+	//nsIMailGlue implementation
+	sanitize: function MG_sanitize(aParentWindow) {
+		this._sanitizer.sanitize(aParentWindow);
+  },
+
   _onProfileStartup: function MailGlue__onProfileStartup() {
     TBDistCustomizer.applyPrefDefaults();
 
     // handle any migration work that has to happen at profile startup
     MailMigrator.migrateAtProfileStartup();
 
     // check if we're in safe mode
     if (Services.appinfo.inSafeMode) {
@@ -90,13 +102,14 @@ MailGlue.prototype = {
                         { contentPage: "about:newaddon?id=" + aAddon.id,
                           clickHandler: null });
       });
     });
   },
 
   // for XPCOM
   classID: Components.ID("{eb239c82-fac9-431e-98d7-11cacd0f71b8}"),
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
+                                         Ci.nsIMailGlue]),
 };
 
 var components = [MailGlue];
 var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
new file mode 100644
--- /dev/null
+++ b/mail/components/nsIMailGlue.idl
@@ -0,0 +1,21 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIDOMWindow;
+
+[scriptable, uuid(bc873177-ea0c-4714-b26c-f89c071107ce)]
+interface nsIMailGlue : nsISupports
+{
+  /** 
+   * Deletes privacy sensitive data according to user preferences
+   *
+   * @param aParentWindow an optionally null window which is the parent of the 
+   *        sanitization dialog
+   *
+   */
+  void sanitize(in nsIDOMWindow aParentWindow);
+
+};
--- a/mail/locales/en-US/chrome/messenger/messenger.dtd
+++ b/mail/locales/en-US/chrome/messenger/messenger.dtd
@@ -502,16 +502,18 @@ you can use these alternative items. Oth
 <!ENTITY runJunkControls.accesskey "C">
 <!ENTITY deleteJunk.label "Delete Mail Marked as Junk in Folder">
 <!ENTITY deleteJunk.accesskey "D">
 <!ENTITY importCmd.label "Import…">
 <!ENTITY importCmd.accesskey "m">
 <!ENTITY errorConsoleCmd.label "Error Console">
 <!ENTITY errorConsoleCmd.accesskey "E">
 <!ENTITY errorConsoleCmd.commandkey "j">
+<!ENTITY clearRecentHistory.label "Clear Recent History…">
+<!ENTITY clearRecentHistory.accesskey "H">
 <!ENTITY accountManagerCmd.label "Account Settings…">
 <!ENTITY accountManagerCmd.accesskey "S">
 <!-- LOCALIZATION NOTE (accountManagerCmdUnix.accesskey): belongs to accountManagerCmd.label,
         which is placed under the Edit menu on Unix systems -->
 <!ENTITY accountManagerCmdUnix.accesskey "A">
 
 <!-- Mail Toolbar -->
 <!ENTITY getMsgButton.label "Get Mail">
--- a/mail/locales/en-US/chrome/messenger/messenger.properties
+++ b/mail/locales/en-US/chrome/messenger/messenger.properties
@@ -695,8 +695,23 @@ crashedpluginsMessage.title=The %S plugi
 crashedpluginsMessage.reloadButton.label=Reload page
 crashedpluginsMessage.reloadButton.accesskey=R
 crashedpluginsMessage.submitButton.label=Submit a crash report
 crashedpluginsMessage.submitButton.accesskey=S
 crashedpluginsMessage.learnMore=Learn More…
 carbonFailurePluginsMessage.message=This page asks to use a plugin that can only run in 32-bit mode
 carbonFailurePluginsMessage.restartButton.label=Restart in 32-bit mode
 carbonFailurePluginsMessage.restartButton.accesskey=R
+
+# Sanitize
+# LOCALIZATION NOTE (sanitizeDialog2.everything.title): When "Time range to
+# clear" is set to "Everything", the Clear Recent History dialog's title is
+# changed to this.  See UI mockup and comment 11 at bug 480169 -->
+sanitizeDialog2.everything.title=Clear All History
+sanitizeButtonOK=Clear Now
+# LOCALIZATION NOTE (sanitizeEverythingWarning2): Warning that appears when
+# "Time range to clear" is set to "Everything" in Clear Recent History dialog,
+# provided that the user has not modified the default set of history items to clear.
+sanitizeEverythingWarning2=All history will be cleared.
+# LOCALIZATION NOTE (sanitizeSelectedWarning): Warning that appears when
+# "Time range to clear" is set to "Everything" in Clear Recent History dialog,
+# provided that the user has modified the default set of history items to clear.
+sanitizeSelectedWarning=All selected items will be cleared.
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/sanitize.dtd
@@ -0,0 +1,50 @@
+<!-- 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 sanitizePrefs2.title          "Settings for Clearing History">
+<!ENTITY sanitizeDialog2.title         "Clear Recent History">
+
+<!ENTITY sanitizeItems.label          "Clear the following items now:">
+<!ENTITY clearDataSettings2.label     "When I quit &brandShortName;, it should automatically clear all:">
+
+<!-- XXX rearrange entities to match physical layout when l10n isn't an issue -->
+<!-- LOCALIZATION NOTE (clearTimeDuration.*): "Time range to clear" dropdown.
+     See UI mockup at bug 480169 -->
+<!ENTITY clearTimeDuration.label          "Time range to clear: ">
+<!ENTITY clearTimeDuration.accesskey      "T">
+<!ENTITY clearTimeDuration.lastHour       "Last Hour">
+<!ENTITY clearTimeDuration.last2Hours     "Last Two Hours">
+<!ENTITY clearTimeDuration.last4Hours     "Last Four Hours">
+<!ENTITY clearTimeDuration.today          "Today">
+<!ENTITY clearTimeDuration.everything     "Everything">
+<!-- Localization note (clearTimeDuration.suffix) - trailing entity for languages
+that require it.  -->
+<!ENTITY clearTimeDuration.suffix         "">
+<!ENTITY clearTimeDuration.dateColumn     "Visit Date">
+<!ENTITY clearTimeDuration.nameColumn     "Name">
+
+<!-- LOCALIZATION NOTE (detailsProgressiveDisclosure.*): Labels and accesskeys
+     of the "Details" progressive disclosure button.  See UI mockup at bug
+     480169 -->
+<!ENTITY detailsProgressiveDisclosure.label     "Details">
+<!ENTITY detailsProgressiveDisclosure.accesskey "e">
+
+<!ENTITY historySection.label         "History">
+<!ENTITY dataSection.label            "Data">
+
+<!-- LOCALIZATION NOTE (item*): itemHistoryAndDownloads.* and
+     itemBrowsingHistory.* will never be used at the same time, so they can
+     have the same accesskey. -->
+<!ENTITY itemCookies.label                 "Cookies">
+<!ENTITY itemCookies.accesskey             "C">
+<!ENTITY itemCache.label                   "Cache">
+<!ENTITY itemCache.accesskey               "A">
+
+<!-- LOCALIZATION NOTE (sanitizeEverythingUndoWarning): Second warning paragraph
+     that appears when "Time range to clear" is set to "Everything".  See UI
+     mockup at bug 480169 -->
+<!ENTITY sanitizeEverythingUndoWarning     "This action cannot be undone.">
+
+<!ENTITY dialog.width                 "28em">
+<!ENTITY column.width                 "14em">
--- a/mail/locales/jar.mn
+++ b/mail/locales/jar.mn
@@ -181,16 +181,17 @@
   locale/@AB_CD@/messenger/downloadsOverlay.dtd                         (%chrome/messenger/downloadsOverlay.dtd)
   locale/@AB_CD@/messenger/chat.dtd                                     (%chrome/messenger/chat.dtd)
   locale/@AB_CD@/messenger/chat.properties                              (%chrome/messenger/chat.properties)
   locale/@AB_CD@/messenger/addbuddy.dtd                                 (%chrome/messenger/addbuddy.dtd)
   locale/@AB_CD@/messenger/joinChat.dtd                                 (%chrome/messenger/joinChat.dtd)
   locale/@AB_CD@/messenger/imAccounts.dtd                               (%chrome/messenger/imAccounts.dtd)
   locale/@AB_CD@/messenger/imAccounts.properties                        (%chrome/messenger/imAccounts.properties)
   locale/@AB_CD@/messenger/imAccountWizard.dtd                          (%chrome/messenger/imAccountWizard.dtd)
+  locale/@AB_CD@/messenger/sanitize.dtd									(%chrome/messenger/sanitize.dtd)
 % locale messenger-mapi @AB_CD@ %locale/@AB_CD@/messenger-mapi/
   locale/@AB_CD@/messenger-mapi/mapi.properties                         (%chrome/messenger-mapi/mapi.properties)
 % locale messenger-newsblog @AB_CD@ %locale/@AB_CD@/messenger-newsblog/
   locale/@AB_CD@/messenger-newsblog/newsblog.properties                 (%chrome/messenger-newsblog/newsblog.properties)
   locale/@AB_CD@/messenger-newsblog/feed-subscriptions.dtd              (%chrome/messenger-newsblog/feed-subscriptions.dtd)
   locale/@AB_CD@/messenger-newsblog/am-newsblog.dtd                     (%chrome/messenger-newsblog/am-newsblog.dtd)
 % locale messenger-smime @AB_CD@ %locale/@AB_CD@/messenger-smime/
   locale/@AB_CD@/messenger-smime/msgCompSMIMEOverlay.dtd                (%chrome/messenger-smime/msgCompSMIMEOverlay.dtd)
--- a/mail/themes/gnomestripe/jar.mn
+++ b/mail/themes/gnomestripe/jar.mn
@@ -255,9 +255,10 @@ classic.jar:
   skin/classic/messenger/newmailaccount/spinner.gif                     (mail/newmailaccount/spinner.gif)
   skin/classic/messenger/newmailaccount/success-addons.png              (mail/newmailaccount/success-addons.png)
   skin/classic/messenger/newmailaccount/success-border.png              (mail/newmailaccount/success-border.png)
   skin/classic/messenger/newmailaccount/success-compose.png             (mail/newmailaccount/success-compose.png)
   skin/classic/messenger/newmailaccount/success-signature.png           (mail/newmailaccount/success-signature.png)
   skin/classic/messenger/newmailaccount/search.png                      (mail/newmailaccount/search.png)
   skin/classic/messenger/icons/ubuntuone.png                    (mail/icons/ubuntuone.png)
   skin/classic/messenger/icons/yousendit.png                  (mail/icons/yousendit.png)
+  skin/classic/messenger/sanitizeDialog.css						      (sanitizeDialog.css)  
   skin/classic/messenger/icons/box-logo.png                   (mail/icons/box-logo.png)
new file mode 100644
--- /dev/null
+++ b/mail/themes/gnomestripe/sanitizeDialog.css
@@ -0,0 +1,107 @@
+/* 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/. */
+
+#sanitizeDurationChoice {
+  -moz-margin-end: 0;
+}
+
+/* Align the duration label with the warning box and item list */
+#sanitizeDurationLabel {
+  -moz-margin-start: 3px;
+}
+
+
+/* Hide the duration dropdown suffix label if it's empty.  Otherwise it
+   takes up a little space, causing the end of the dropdown to not be aligned
+   with the warning box. */
+#sanitizeDurationSuffixLabel[value=""] {
+  display: none;
+}
+
+
+/* Places tree */
+#placesTreechildren::-moz-tree-row(selected),
+#placesTreechildren::-moz-tree-row(grippyRow) {
+  background: #999;
+}
+
+#placesTreechildren::-moz-tree-cell-text(selected) {
+  color: #111;
+}
+
+
+/* Sanitize everything warning box */
+#sanitizeEverythingWarningBox {
+  background-color: Window;
+  border: 1px solid ThreeDDarkShadow;
+  border-radius: 5px;
+  padding: 16px;
+}
+
+#sanitizeEverythingWarningIcon {
+  list-style-image: url("moz-icon://stock/gtk-dialog-warning?size=dialog");
+  padding: 0;
+  margin: 0;
+}
+
+#sanitizeEverythingWarningDescBox {
+  padding: 0 16px;
+  margin: 0;
+}
+
+
+/* Progressive disclosure button */
+#detailsExpanderWrapper {
+  padding: 0;
+  margin-top: 6px;
+  margin-bottom: 6px;
+  -moz-margin-start: -6px;
+  -moz-margin-end: 0;
+}
+
+.expander-up,
+.expander-down {
+  min-width: 0;
+  padding: 2px 0;
+  -moz-padding-start: 2px;
+}
+
+.expander-up {
+  list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
+}
+
+.expander-down {
+  list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif");
+}
+
+.expander-down:hover:active {
+  list-style-image: url("chrome://global/skin/arrow/arrow-dn-hov.gif");
+}
+
+.expander-up:hover:active {
+  list-style-image: url("chrome://global/skin/arrow/arrow-up-hov.gif");
+}
+
+
+/* Make the item list the same width as the warning box */
+#itemList {
+  -moz-margin-start: 0;
+  -moz-margin-end: 0;
+}
+
+/* Without this a useless scrollbar appears in the listbox when its rows
+   attribute is set to the total number of listitems, as it is currently.  See
+   bug 489958 comment 14 and bug 491788. */
+#itemList > listitem {
+  padding: 1px 0;
+}
+
+
+/* Align the last dialog button with the end of the warning box */
+.prefWindow-dlgbuttons {
+  -moz-margin-end: 0;
+}
+.dialog-button[dlgtype="accept"] {
+  -moz-margin-end: 0;
+}
--- a/mail/themes/pinstripe/jar.mn
+++ b/mail/themes/pinstripe/jar.mn
@@ -299,11 +299,16 @@ classic.jar:
   skin/classic/messenger/newmailaccount/accountProvisioner.css          (mail/newmailaccount/accountProvisioner.css)
   skin/classic/messenger/newmailaccount/search.gif                      (mail/newmailaccount/search.gif)
   skin/classic/messenger/newmailaccount/spinner.gif                     (mail/newmailaccount/spinner.gif)
   skin/classic/messenger/newmailaccount/success-addons.png              (mail/newmailaccount/success-addons.png)
   skin/classic/messenger/newmailaccount/success-border.png              (mail/newmailaccount/success-border.png)
   skin/classic/messenger/newmailaccount/success-compose.png             (mail/newmailaccount/success-compose.png)
   skin/classic/messenger/newmailaccount/success-signature.png           (mail/newmailaccount/success-signature.png)
   skin/classic/messenger/newmailaccount/search.png                      (mail/newmailaccount/search.png)
-  skin/classic/messenger/icons/ubuntuone.png                    (mail/icons/ubuntuone.png)
-  skin/classic/messenger/icons/yousendit.png                  (mail/icons/yousendit.png)
+  skin/classic/messenger/icons/ubuntuone.png							(mail/icons/ubuntuone.png)
+  skin/classic/messenger/icons/yousendit.png							(mail/icons/yousendit.png)
+  skin/classic/messenger/places/expander-closed.png							(places/expander-closed.png)						
+  skin/classic/messenger/places/expander-closed-active.png					(places/expander-closed-active.png)
+  skin/classic/messenger/places/expander-open.png							(places/expander-open.png)
+  skin/classic/messenger/places/expander-open-active.png					(places/expander-open-active.png)
+  skin/classic/messenger/sanitizeDialog.css									(sanitizeDialog.css)  
   skin/classic/messenger/icons/box-logo.png                      (mail/icons/box-logo.png)
new file mode 100644
index 0000000000000000000000000000000000000000..7ef5f04f9ea9aec76eb9bee7af5aaa2c74a3fb01
GIT binary patch
literal 1329
zc$@(-1<v}3P)<h;3K|Lk000e1NJLTq000;O000*V1^@s65h0H)00004XF*Lt007q5
z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$!%0LzRCwBA
zWB>w}q%Qvd{}~Q`d;d)L|NnnX3`l^H0YCVU#AasU_{k+CyLtEQ+;AZG-+!Q?009Kj
z&+L-izfW6N*UrPqih-St1;b!QMu<U-$Oit$wCK&dPYhdj9{lt8;k{Y=7nJ4#E%*lz
zKp@jNzJGjf>FJWq@E2&~g(rU*K7IdB&<DuoGXWKe@Gvo`iSskqSQ@h|yn4nPC|m@@
zKLG*=WC8o1-#=K{SQ!~ELJenx>SBc2zz88woc|vt075|g>hnJakmp4Nxf%Zc`^^KC
zWCK|M5I~^tW&x@C3uJu!4l<YtVmL5d7@2_><UD4GFe8WtV@5C=EDywBF97k2&;J=%
z5HZLMA^-vi9^hbC0!;xM05lw|jtLP=|DihmqX*qTARDCaKO@+YXi>ue5I`(2#Y{jK
zFad)J<QPU6h6W82vVn|{Ac2|<<U=?hF^~foncx8m1^@vBw%|WV5hKLwNIqsbvUW1V
zqid&tmNR3-_P@V>8D!Lr80^Cffr$fX#y^OKjEtyC0Rjl>ga6<#X9oEK5(QvyE9zS@
zTs^W8XC6@0vt(dm0qO>Z%|B37{exJ*z=*H|Ab^-)sRCpmNHH@Iv#>#EMO{+{+t5rz
zkRf3U-*^UP11p9<fBrN428PeKAHWp&^Do2C-~SkX{QC6|W&uC|K_VIGKak5=SRko|
znF$gnpfI)Y3S)S7`#i(FOD7oqfr8=Re+FS0O$G_0Fowr3z5|ma16UlChd@E~o%;{N
z&u>5BaSaea5Far82PZdXRtN_9gq4+n;SbQT_n-bS==$U{FtZDQUCYGE!C)Ct0+eTB
zU;$z_C}v@0W?%)TQD!F8NB{^Rco2caK|TN_nQuS-F+6+oi{a(F-(WU3pAdt6bQ#!J
z=KkpnLK3nJY-|vNS=k_tVg+FqMo4NziUWWEVu2?(purzL{bl(2^)EOt038H0gb^Ix
zpp+%AW5S^C9KxVw;|Vqdl;A-@^6wu=&3|wN|Ai$`MnrA^2q3TpfByVq`10i+!`JWs
zz%F57W<<mVG>?E1flX)z+&!R@k_ni(fJG()Gf@3+P_+L24^QGS01!Z63w{EF0VKx8
z0?GOygIRz+V1X46j1WIFLbLQgpbJ5zIy0z<`O657Xof$KOa{tJ|B-?SAb_An#Xqn?
zps-{C<p-cBE64}1G6<xQ1>r1E&@lXi1`iX=aG)MgNHhKi=PMWh2q1V-0SXpTZYGA0
ze;|glLJbF5!ieT=W>C;DgK{%a{2xUBA0S%{REGX$L@BBO0tjpY3oFMTpf_1mg%}y`
ze+H)IKM;dKK4F5CfuJH6QDOu6e}QWLGC>RmdYnO!6PUC485pkJ{0#Ih>ra>k009Kj
z_lKQZ;>w2Y+YN%e-57L4SRgKk8jS3ECTKwi3xL1>AbfBJ1kx|xeqcCs?BpL-R<7e9
zX^<L#00L>{7L-)clvFd>_T%$&k-xuxFd|A*c-g{$Tv7jnRcZg>6xbp*PX2$KJW|&$
z?p@#q6nY9wX+Hr1h!I-M3jnbc5DPLOLW5KQvIi72Z-DqY5Pt#H$p8Vwh!j+upz4zW
n)v=@kV9YT5fMRf~0wBNu(gkh+k|I`<00000NkvXXu0mjf(9$K;
new file mode 100644
index 0000000000000000000000000000000000000000..7850c9e9510b196e7b34398d2c028a457c901418
GIT binary patch
literal 837
zc$@)61G@Z)P)<h;3K|Lk000e1NJLTq000;O000*V1^@s65h0H)00004XF*Lt007q5
z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!*GWV{RCwBA
zWB`Jmo*n@{KE5Mw-n`NL_wOGQ1DSx0jqR7HsOYxD#Kd4A_uv2j{}})R2qextXU?3X
z$B!TX|NHmv|CE5wpFjWKzJ2?jsZ*!U0Gi7LvH&1}Sbz+Uw{PE?nwy)0UGe?<cLtzE
zB)guSot=S)hljzyz<~Mk<;&hcAyy#%2@pUa3)p}C`o+q~$Vj%~An^0&PX>?~TwGiX
zK=ZgjAqEl#2q2IJEHFiX{`>(eA{PJ+2I~jLBRJ?m1V8|R4TlOaz#@fQfTSPJ00<x!
zWC==Kk8H``zklI;fB<5_=kn>(r!$;BeVT!pnHfV4WQd`mAwzC%E<T?y00a<<1x!q+
zS-`@=f?>;+EjV2Zl1JAAibrG%00M{!J&2I8iHQkAYHBK0!((D%7|hJfz^M*|zkT}#
z#?Ykx2c`}nfS8aY85;-=4rVYlH3d5Yqz)7`ii(O1&d$yZuU@@kc=zrd7y~mI7=zS&
z`SJyx)&T+t#R6p4gS-y%E>JN;e0)4O6M+l|76%NOnVH~t0jWX9PykOY00D#&fFOfG
zF8%T22iR2~K70VP1q1{bva_?n^0Be83{p~3SPchZ^ppq?KrFBn0RmsYeg)@dxa~+0
z2rL2^e0_bvL4zK#=qU&}k^uq;ZUIOTl-==Z1_c$7c>(SXfB<5Fl_S`aDK!8<0KxMC
zEMh4EApOuFg8Kj<fKW0Ts3ZhMD!G80n;V`NU;rS1SfDol1X{ulQUJ0HR4S4RI5;>M
zI5{~PUcP(@;=)}C5I`Uc{s1jFyL0DGD;F0R23}rXvVHLB(<cUC&G;LbXbytX4oD0j
zfIwlzEh8hNVQg%?5tu}!fDul1kqQjr-$0*SSigRK1d#g_7#cqT0*Db>F$e&$6c7tS
zeMOEXpojz|$2UOy9EiUFE%*lzK#WL1#R;lD(Q`M6;14wXf52K5009O7Gh2ejfzj5Q
P00000NkvXXu0mjfLdQsv
new file mode 100644
index 0000000000000000000000000000000000000000..673ead568d21bf9fb2d3ff1d729d8326541740e6
GIT binary patch
literal 1329
zc$@(-1<v}3P)<h;3K|Lk000e1NJLTq000;O000*V1^@s65h0H)00004XF*Lt007q5
z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$!%0LzRCwBA
zWB>w}q%Qvd{}~Q`d;d)L|NnnX3`l^H0YCVU#AasU_{k+CyLtEQ+;AZG-+!Q?009Kj
z&+L-izfW6N*UrPqih-St1;b!QMu<U-$Oit$wCK&dPYhdj9{lt8;k{Y=7nJ4#E%*lz
zKp@jNzJGjf>FJWq@E2&~g(rU*K7IdB&<DuoGXWKe@Gvo`iSskqSQ@h|yn4nPC|m@@
zKLG*=WC8o1-#=K{SQ!~ELJenx>SBc2zz88woc|vt075|g>hnJakmp4Nxf%Zc`^^KC
zWCK|M5I~^tW&x@C3uJu!4l<YtVmL5d7@2_><UD4GFe8WtV@5C=EDywBF97k2&;J=%
z5HZLMA^-vi9^hbC0!;xM05lw|jtLP=|DihmqX*qTARDCaKO@+YXi>ue5I{^Y#Y{jK
zFad*!3F<0F79bmJArk{L5VHdDsjYK>V*kN>7G{VXNIgssGt|e7NcIB+5ZHqMjQ_zx
zOi)EEFbwn`D-eU|XLrvsTspX#;nwNx3@ogmBncD;dWi+-C}tLjKCnfMs0jlgfS^A3
z4-Ru?CPsvdKt5oBuz!4i&#-q%CpZ9(Z<xvO`Q1|nW~jknHB3++FhVR~U_{sf5I{_@
zQ~?S{kYbP~7B;A>Kp1Gy{-r$(-#@<tYySP~JHy_^oj?~ueEjFne}><{Wc2L^Fa`en
z%kcB}KZYN_e*J@401!ZsNdEs1oJv4J0iv0iAaMeU)N^}RF+99_3heKH|3LUZ!^4|b
z8MZE&%b?>F4NQ^{aZn!m3k>P++<zE;e)|cJYk&ZP_y8DjU@x*lFvusYz;M2M<rKr-
zWz)f~`t|ES*tP$lZo9UBDZ|S<rx@5+nZTHZl^GacOyFQfjs$=JVu1w_NF3w?kp6Gq
z|1o_1{)gex@gode0utcV!ibiO{{d}!aqAR=ysjm~A87jg_ZONPk>UU#fLP#(8R(Y}
zpZ+p@{rVT27l008unErvhdVPPYJPy(0tyn4j~IcekQo$AumsA8$PEAi1h(MMpMMNr
zzJOf)4;VC%BnpoUXdYoiE@S_JiU**tftd?fWP+3EZ;;pj{)c61H~<JBumwMV`~zFe
z#sW=lOwcqAD;^jjerAMv;UCb2pi-R~RK)yc1V=Q(9|mwH1EsA0NI?V;K+vM%AJ`yJ
z1hath11N)md;lwhKnht9&ieZw;){R(pg#KpDK1z+A<g(7oUdR2Ab?n4VG9ZtQEn!N
zkAEPBvqB9AS;C0sZDvr=Fhe8tA4ESWqQyXE=x;`pq6#2@z!tEua{K{$lSNgCk>UPl
zU|RkIF&N|%CP*0wDsmB#4CMa>s`<+VF&OA^20=~+21R~g^1b;P=v&sGFbe<z2&C^1
zJGaD@4coUH1bMqL=!mdDTn;rD+4Ug$|9?bE`uh*U2WLPa{qpSxhC|0r{$XY1Iu4Qs
zsR0NekXCL%Nfk{=HIr>WK0g=v`}+qYxWIy?I7r#TfR>0Lw)}@vV2ju|`Tue9NL|0U
zcYz;J=qWIz{R9XgMrbiF0K`&2EXaTe4N?Kf9#GJ{0pjOC`~_4e0|XEwQc!V%s!s+~
n$C3(wF~jf!iovZ4fB*vk{nvi;!|I_m00000NkvXXu0mjfixE5#
new file mode 100644
index 0000000000000000000000000000000000000000..76553571d9744faf08b3ca6548eb1ee429fa9cc8
GIT binary patch
literal 818
zc$@(;1I_%2P)<h;3K|Lk000e1NJLTq000;O000*V1^@s65h0H)00004XF*Lt007q5
z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!#7RU!RCwBA
zWB`Jmo*n@{KE5Mw-n`NL_wOGQ1DSx0jqR7HsOYxD#Kd4A_uv2j{}})R2qextXU?3X
z$B!TX|NHmv|CE5wpFjWKzJ2?jsZ*!U0Gi7LvH&1}Sbz+Uw{PE?nwy)0UGe?<cLtzE
zB)guSot=S)hljzyz<~Mk<;&hcAyy#%2@pUa3)p}C`o+q~$Vj%~An^0&PX>?~TwGiX
zK=ZgjAqEl#2q2IJEHFiX{`>(eA{PJ+2I~jLBRJ?m1V8|R4TlOaz#@fQfTSPJ00<x^
zWC@V%`0%`W^T3Y5rv?Q6{{0KL6d-_@h;{k-^XD1XuV2rwYu7GPe8K<_KqwY4F)?Aq
zA3uI%=<V$VtD8G_F2nQZ&vB{+sX?{?Ab^MpqW=DVhWGE^!;>+{GMGM4ssrI~-@bt{
zRLvil1pooWgdEA(z}mHI8BU)*4K@s<4ivt?bj~ns+BAk&uU;{{d-o2Eftd`9L2ABy
z`2tVt00D$z0kW$>-aU2d6vK=eGr%qcC1H@^AhjUN)~#Cyju-SGf&zG22M8b*WY@yd
zFeuZ2g5tn|0}Q~j1z95;fYe>MaDl<p)RY0;3}gThKrG0~>g(69V1r>GB_)Ndynr0Z
z009KI03--<IX2glVF}zD00G1TD@S0-l-d9wfLLJOf<-JP04X29eE<+ZEXer)R1*I9
z@q=s&xVgFEc>x9h0*D1_^G~29>>vdo%Rr?fseprngMpKili}sdmmn_Ol>h+*vfvNU
zg0nk!?zD1oabe))<t5t(pFVwJ0M?AZfr;iIDD8m600IaUR@^c&G8)Fl#v6f2R0<g3
zWLF5lApQ;X$pv7c7y;xy1%}2?fB<5IRty3_ECs}ZP+yT_2`C~#$?**kKL_G3Knwl>
w1P~)qP;r8)PgwCmCinvl{~xec1weoS0A>@TalLnur2qf`07*qoM6N<$f)Wy5t^fc4
new file mode 100644
--- /dev/null
+++ b/mail/themes/pinstripe/sanitizeDialog.css
@@ -0,0 +1,104 @@
+/* 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/. */
+
+/* Align the duration label with the warning box and item list */
+#sanitizeDurationLabel {
+  -moz-margin-start: 1px;
+}
+
+
+/* Hide the duration dropdown suffix label if it's empty.  Otherwise it
+   takes up a little space, causing the end of the dropdown to not be aligned
+   with the warning box. */
+#sanitizeDurationSuffixLabel[value=""] {
+  display: none;
+}
+
+
+/* Places tree */
+#placesTreechildren::-moz-tree-row(selected),
+#placesTreechildren::-moz-tree-row(grippyRow) {
+  background: #999;
+}
+
+#placesTreechildren::-moz-tree-cell-text(selected) {
+  color: #111;
+}
+
+
+/* Sanitize everything warning box */
+#sanitizeEverythingWarningBox {
+  background-color: Window;
+  border: 1px solid ThreeDDarkShadow;
+  border-radius: 5px;
+  padding: 16px;
+}
+
+#sanitizeEverythingWarningIcon {
+  list-style-image: url("chrome://global/skin/icons/warning-large.png");
+  padding: 0;
+  margin: 0;
+}
+
+#sanitizeEverythingWarningDescBox {
+  padding: 0 16px;
+  margin: 0;
+}
+
+
+/* Progressive disclosure button */
+#detailsExpanderWrapper {
+  padding: 0;
+  margin-top: 6px;
+  margin-bottom: 6px;
+  -moz-margin-start: -2px;
+  -moz-margin-end: 0;
+}
+
+.expander-up,
+.expander-down {
+  -moz-appearance: none;
+  min-width: 0;
+  padding: 0;
+  margin: 0;
+}
+
+.expander-up {
+  list-style-image: url("chrome://messenger/skin/places/expander-open.png");
+}
+
+.expander-up:hover:active {
+  list-style-image: url("chrome://messenger/skin/places/expander-open-active.png");
+}
+
+.expander-down {
+  list-style-image: url("chrome://messenger/skin/places/expander-closed.png");
+}
+
+.expander-down:hover:active {
+  list-style-image: url("chrome://messenger/skin/places/expander-closed-active.png");
+}
+
+
+/* Make the item list the same width as the warning box */
+#itemList {
+  -moz-margin-start: 0;
+  -moz-margin-end: 0;
+}
+
+/* Without this a useless scrollbar appears in the listbox when its rows
+   attribute is set to the total number of listitems, as it is currently.  See
+   bug 489958 comment 14 and bug 491788. */
+#itemList > listitem {
+  padding: 1px 0;
+}
+
+
+/* Align the last dialog button with the end of the warning box */
+.prefWindow-dlgbuttons {
+  -moz-margin-end: 0;
+}
+.dialog-button[dlgtype="accept"] {
+  -moz-margin-end: 0;
+}
--- a/mail/themes/qute/jar.mn
+++ b/mail/themes/qute/jar.mn
@@ -267,16 +267,17 @@ classic.jar:
   skin/classic/messenger/newmailaccount/accountProvisioner.css          (mail/newmailaccount/accountProvisioner.css)
   skin/classic/messenger/newmailaccount/search.gif                      (mail/newmailaccount/search.gif)
   skin/classic/messenger/newmailaccount/spinner.gif                     (mail/newmailaccount/spinner.gif)
   skin/classic/messenger/newmailaccount/success-addons.png              (mail/newmailaccount/success-addons.png)
   skin/classic/messenger/newmailaccount/success-border.png              (mail/newmailaccount/success-border.png)
   skin/classic/messenger/newmailaccount/success-compose.png             (mail/newmailaccount/success-compose.png)
   skin/classic/messenger/newmailaccount/success-signature.png           (mail/newmailaccount/success-signature.png)
   skin/classic/messenger/newmailaccount/search.png                      (mail/newmailaccount/search.png)
+  skin/classic/messenger/sanitizeDialog.css					  (sanitizeDialog.css)
  skin/classic/messenger/icons/ubuntuone.png                    (mail/icons/ubuntuone.png)
  skin/classic/messenger/icons/yousendit.png                  (mail/icons/yousendit.png)
   skin/classic/messenger/icons/box-logo.png                  (mail/icons/box-logo.png)
 #ifdef XP_WIN
 % skin communicator classic/1.0 %skin/classic/aero/communicator/ os=WINNT osversion>=6
   skin/classic/aero/communicator/communicator.css                       (mail/communicator.css)
   skin/classic/aero/communicator/smileys.css                            (mail/smileys.css)
   skin/classic/aero/communicator/icons/smileys/smiley-smile.png         (mail/icons/smiley-smile-aero.png)
@@ -528,10 +529,11 @@ classic.jar:
   skin/classic/aero/messenger/newmailaccount/spinner.gif                     (mail/newmailaccount/spinner.gif)
   skin/classic/aero/messenger/newmailaccount/success-addons.png              (mail/newmailaccount/success-addons.png)
   skin/classic/aero/messenger/newmailaccount/success-border.png              (mail/newmailaccount/success-border.png)
   skin/classic/aero/messenger/newmailaccount/success-compose.png             (mail/newmailaccount/success-compose.png)
   skin/classic/aero/messenger/newmailaccount/success-signature.png           (mail/newmailaccount/success-signature.png)
   skin/classic/aero/messenger/newmailaccount/search.png                      (mail/newmailaccount/search.png)
   skin/classic/aero/messenger/icons/ubuntuone.png                    (mail/icons/ubuntuone.png)
   skin/classic/aero/messenger/icons/yousendit.png                  (mail/icons/yousendit.png)
+  skin/classic/aero/messenger/sanitizeDialog.css						 (sanitizeDialog.css)
   skin/classic/aero/messenger/icons/box-logo.png                   (mail/icons/box-logo.png)
 #endif
new file mode 100644
--- /dev/null
+++ b/mail/themes/qute/sanitizeDialog.css
@@ -0,0 +1,93 @@
+/* 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/. */
+
+#sanitizeDurationChoice {
+  -moz-margin-end: 0;
+}
+
+/* Align the duration label with the warning box and item list */
+#sanitizeDurationLabel {
+  -moz-margin-start: 3px;
+}
+
+
+/* Hide the duration dropdown suffix label if it's empty.  Otherwise it
+   takes up a little space, causing the end of the dropdown to not be aligned
+   with the warning box. */
+#sanitizeDurationSuffixLabel[value=""] {
+  display: none;
+}
+
+
+/* Places tree */
+#placesTreechildren::-moz-tree-row(selected),
+#placesTreechildren::-moz-tree-row(grippyRow) {
+  background: #999;
+}
+
+#placesTreechildren::-moz-tree-cell-text(selected) {
+  color: #111;
+}
+
+
+/* Sanitize everything warning box */
+#sanitizeEverythingWarningBox {
+  background-color: Window;
+  border: 1px solid ThreeDDarkShadow;
+  border-radius: 5px;
+  padding: 16px;
+}
+
+#sanitizeEverythingWarningIcon {
+  list-style-image: url("chrome://global/skin/icons/warning-large.png");
+  padding: 0;
+  margin: 0;
+}
+
+#sanitizeEverythingWarningDescBox {
+  padding: 0 16px;
+  margin: 0;
+}
+
+
+/* Progressive disclosure button */
+#detailsExpanderWrapper {
+  padding: 0;
+  margin: 6px 0;
+}
+
+.expander-up,
+.expander-down {
+  min-width: 0;
+  margin: 0;
+}
+
+.expander-up > .button-box,
+.expander-down > .button-box {
+  padding: 0;
+}
+
+.expander-up {
+  list-style-image: url("chrome://global/skin/icons/collapse.png");
+}
+
+.expander-down {
+  list-style-image: url("chrome://global/skin/icons/expand.png");
+}
+
+
+/* Make the item list the same width as the warning box */
+#itemList {
+  -moz-margin-start: 0;
+  -moz-margin-end: 0;
+}
+
+
+/* Align the last dialog button with the end of the warning box */
+.prefWindow-dlgbuttons {
+  -moz-margin-end: 0;
+}
+.dialog-button[dlgtype="cancel"] {
+  -moz-margin-end: 0;
+}