Bug 457296 - Part 4: migrate RemoteContent pref (Implement separate whitelist for addresses/domains allowed to load remote images for email. r=mconley, r=standard8, a=standard8
authorMagnus Melin <mkmelin+mozilla@iki.fi>
Mon, 28 Apr 2014 13:31:10 +0300
changeset 19953 af30e12503ab60017b490d09d4108696e77cb2fd
parent 19952 45cc03b40060d5d5aa8f8bd3c20082e1e709d723
child 19954 6991232407063296e14bd1bc26941b5330cc36c9
push id1151
push usermbanner@mozilla.com
push dateMon, 09 Jun 2014 22:14:36 +0000
treeherdercomm-beta@ce127428ad7d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley, standard8, standard8
bugs457296
Bug 457296 - Part 4: migrate RemoteContent pref (Implement separate whitelist for addresses/domains allowed to load remote images for email. r=mconley, r=standard8, a=standard8
mail/base/content/mailWindowOverlay.js
mail/base/content/mailWindowOverlay.xul
mail/components/addrbook/content/abCardOverlay.js
mail/components/addrbook/content/abCardOverlay.xul
mail/locales/en-US/chrome/messenger/addressbook/abCardOverlay.dtd
mail/locales/en-US/chrome/messenger/messenger.dtd
mailnews/addrbook/public/nsIAbCard.idl
mailnews/addrbook/public/nsIAddrDatabase.idl
mailnews/addrbook/src/nsAbCardProperty.cpp
mailnews/addrbook/src/nsAddrDatabase.cpp
mailnews/addrbook/src/nsAddrDatabase.h
mailnews/base/test/unit/data/remoteContent.mab
mailnews/base/test/unit/test_accountMigration.js
mailnews/base/util/mailnewsMigrator.js
mailnews/import/test/unit/resources/import_helper.js
--- a/mail/base/content/mailWindowOverlay.js
+++ b/mail/base/content/mailWindowOverlay.js
@@ -3047,89 +3047,28 @@ function LoadMsgWithRemoteContent()
   // change the "remoteContentBar" property on it
   // then reload the message
 
   setMsgHdrPropertyAndReload("remoteContentPolicy", kAllowRemoteContent);
   window.content.focus();
 }
 
 /**
- *  Reloads the message after adjusting the remote content policy for the sender.
- *  Iterate through the local address books looking for a card with the same e-mail address as the
- *  sender of the current loaded message. If we find a card, update the allow remote content field.
- *  If we can't find a card, prompt the user with a new AB card dialog, pre-selecting the remote content field.
- */
-function allowRemoteContentForSender()
-{
-  // get the sender of the msg hdr
-  let msgHdr = gMessageDisplay.displayedMessage;
-  if (!msgHdr)
-    return;
-
-  let names = {};
-  let addresses = {};
-
-  MailServices.headerParser.parseHeadersWithArray(msgHdr.author, addresses, names, {});
-  let authorEmailAddress = addresses.value[0];
-  let authorDisplayName = names.value[0];
-
-  // search through all of our local address books looking for a match.
-  let enumerator = MailServices.ab.directories;
-  var cardForEmailAddress;
-  var addrbook;
-  while (!cardForEmailAddress && enumerator.hasMoreElements())
-  {
-    addrbook = enumerator.getNext()
-                         .QueryInterface(Components.interfaces.nsIAbDirectory);
-    // Try/catch because some cardForEmailAddress functions may not be
-    // implemented.
-    try {
-      // If its a read-only book, don't find a card as we won't be able
-      // to modify the card.
-      if (!addrbook.readOnly)
-        cardForEmailAddress = addrbook.cardForEmailAddress(authorEmailAddress);
-    } catch (e) {}
-  }
-
-  var allowRemoteContent = false;
-  if (cardForEmailAddress)
-  {
-    // set the property for remote content
-    cardForEmailAddress.setProperty("AllowRemoteContent", true);
-    addrbook.modifyCard(cardForEmailAddress);
-    allowRemoteContent = true;
-  }
-  else
-  {
-    let args = {primaryEmail:authorEmailAddress, displayName:authorDisplayName,
-                allowRemoteContent:true};
-    // create a new card and set the property
-    window.openDialog("chrome://messenger/content/addressbook/abNewCardDialog.xul",
-                      "", "chrome,resizable=no,titlebar,modal,centerscreen", args);
-    allowRemoteContent = args.allowRemoteContent;
-  }
-
-  // Reload the message if we've updated the remote content policy for the sender.
-  if (allowRemoteContent)
-    ReloadMessage();
-}
-
-/**
  * Populate the remote content options for the current message.
  */
 function onRemoteContentOptionsShowing(aEvent) {
   let hosts = aEvent.target.value ? aEvent.target.value.split(" ") : [];
 
   let addresses = {};
   MailServices.headerParser.parseHeadersWithArray(
     gMessageDisplay.displayedMessage.author, addresses, {}, {});
   let authorEmailAddress = addresses.value[0];
   // Needs bug 457296 policy patch to actually work, but I don't want to
   // keep this bug hostage for that, so just if-false it for now.
-  if (false && authorEmailAddress)
+  if (authorEmailAddress)
     hosts.splice(0, 0, authorEmailAddress);
 
   let messengerBundle = document.getElementById("bundle_messenger");
 
   // Out with the old...
   let childNodes = aEvent.target.childNodes;
   for (let i = childNodes.length - 1; i >= 0; i--) {
     if (childNodes[i].getAttribute("class") == "allow-remote-uri")
@@ -3141,26 +3080,26 @@ function onRemoteContentOptionsShowing(a
     let uri = Services.io.newURI(
       host.contains("@") ? "mailto:" + host : "http://" + host, null, null);
 
     let menuitem = document.createElement("menuitem");
     menuitem.setAttribute("label",
       messengerBundle.getFormattedString("remoteAllow", [host]));
     menuitem.setAttribute("value", uri.spec);
     menuitem.setAttribute("class", "allow-remote-uri");
-    menuitem.setAttribute("oncommand", "allowRemoteContentForSite(this.value);");
+    menuitem.setAttribute("oncommand", "allowRemoteContentForURI(this.value);");
     aEvent.target.appendChild(menuitem);
   }
 }
 
 /**
  * Add privileges to display remote content for the given uri.
  * @param aUriSpec |String| uri for the site to add permissions for.
  */
-function allowRemoteContentForSite(aUriSpec) {
+function allowRemoteContentForURI(aUriSpec) {
   let uri = Services.io.newURI(aUriSpec, null, null);
   Services.perms.add(uri, "image", Services.perms.ALLOW_ACTION);
   ReloadMessage();
 }
 
 /**
  * Displays fine-grained, per-site preferences for remote content.
  */
--- a/mail/base/content/mailWindowOverlay.xul
+++ b/mail/base/content/mailWindowOverlay.xul
@@ -983,21 +983,16 @@
 #ifdef XP_WIN
               label="&editRemoteContentSettings.label;"
               accesskey="&editRemoteContentSettings.accesskey;"
 #else
               label="&editRemoteContentSettingsUnix.label;"
               accesskey="&editRemoteContentSettingsUnix.accesskey;"
 #endif
               oncommand="editRemoteContentSettings();"/>
-<!--    <menuitem id="remoteContentOptionAllowForAddress"
-              label="&remoteContentOptionAllowForAddress.label;"
-              accesskey="&remoteContentOptionAllowForAddress.accesskey;"
-              oncommand="allowRemoteContentForSender();"/>
--->
   </menupopup>
 
   <menupopup id="phishingOptions">
     <menuitem id="phishingOptionIgnore"
               label="&phishingOptionIgnore.label;"
               accesskey="&phishingOptionIgnore.accesskey;"
               oncommand="IgnorePhishingWarning();"/>
     <menuitem id="phishingOptionSettings"
--- a/mail/components/addrbook/content/abCardOverlay.js
+++ b/mail/components/addrbook/content/abCardOverlay.js
@@ -3,17 +3,17 @@
  * 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");
 Components.utils.import("resource:///modules/mailServices.js");
 
 const kNonVcardFields =
         ["NickNameContainer", "SecondaryEmailContainer", "ScreenNameContainer",
-         "customFields", "allowRemoteContent", "preferDisplayName"];
+         "customFields", "preferDisplayName"];
 
 const kPhoneticFields =
         ["PhoneticLastName", "PhoneticLabel1", "PhoneticSpacer1",
          "PhoneticFirstName", "PhoneticLabel2", "PhoneticSpacer2"];
 
 // Item is |[dialogField, cardProperty]|.
 const kVcardFields =
         [ // Contact > Name
@@ -117,19 +117,16 @@ function OnLoadNewCard()
       // a display name (and stomp on the existing display name)
       // when the user types a first or last name
       if (gEditCard.card.displayName)
         gEditCard.generateDisplayName = false;
     }
     if ("aimScreenName" in window.arguments[0])
       gEditCard.card.setProperty("_AimScreenName",
                                  window.arguments[0].aimScreenName);
-    if ("allowRemoteContent" in window.arguments[0])
-      gEditCard.card.setProperty("AllowRemoteContent",
-                                 window.arguments[0].allowRemoteContent);
 
     if ("okCallback" in window.arguments[0])
       gOkCallback = window.arguments[0].okCallback;
 
     if ("escapedVCardStr" in window.arguments[0]) {
       // hide non vcard values
       HideNonVcardFields();
       gEditCard.card =
@@ -284,28 +281,23 @@ function OnLoadEditCard()
         document.getElementById("UpdatePhoto").disabled      = true;
 
         // And the phonetic fields
         document.getElementById(kPhoneticFields[0]).readOnly = true;
         document.getElementById(kPhoneticFields[3]).readOnly = true;
 
         // Also disable the mail format popup and allow remote content items.
         document.getElementById("PreferMailFormatPopup").disabled = true;
-        document.getElementById("allowRemoteContent").disabled = true;
 
         // And the "prefer display name" checkbox
         document.getElementById("preferDisplayName").disabled = true;
 
         document.documentElement.buttons = "accept";
         document.documentElement.removeAttribute("ondialogaccept");
       }
-      
-      // hide  remote content in HTML field for remote directories
-      if (directory.isRemote)
-        document.getElementById('allowRemoteContent').hidden = true;
     }
   }
 }
 
 /* Registers functions that are called when loading the card
  * values into the contact editor dialog.  This is useful if
  * extensions have added extra fields to the nsIAbCard, and
  * need to display them in the contact editor.
@@ -429,22 +421,16 @@ function NewCardOKButton()
         return false;  // don't close window
 
       // replace gEditCard.card with the card we added
       // so that save listeners can get / set attributes on
       // the card that got created.
       var directory = GetDirectoryFromURI(uri);
       gEditCard.card = directory.addCard(gEditCard.card);
       NotifySaveListeners(directory);
-      if ("arguments" in window && window.arguments[0] &&
-          "allowRemoteContent" in window.arguments[0]) {
-        // getProperty may return a "1" or "0" string, we want a boolean
-        window.arguments[0].allowRemoteContent =
-          gEditCard.card.getProperty("AllowRemoteContent", false) != false;
-      }
     }
   }
 
   return true;  // close the window
 }
 
 // Move the data from the cardproperty to the dialog
 function GetCardValues(cardproperty, doc)
@@ -495,21 +481,16 @@ function GetCardValues(cardproperty, doc
   birthday.onchange = calculateAge;
   var age = doc.getElementById("Age");
   age.onchange = calculateYear;
 
   var popup = document.getElementById("PreferMailFormatPopup");
   if (popup)
     popup.value = cardproperty.getProperty("PreferMailFormat", "");
 
-  var allowRemoteContentEl = document.getElementById("allowRemoteContent");
-  if (allowRemoteContentEl)
-    // getProperty may return a "1" or "0" string, we want a boolean
-    allowRemoteContentEl.checked = cardproperty.getProperty("AllowRemoteContent", false) != false;
-
   var preferDisplayNameEl = document.getElementById("preferDisplayName");
   if (preferDisplayNameEl)
     // getProperty may return a "1" or "0" string, we want a boolean
     preferDisplayNameEl.checked = cardproperty.getProperty("PreferDisplayName", true) != false;
 
   // get phonetic fields if exist
   try {
     doc.getElementById("PhoneticFirstName").value = cardproperty.getProperty("PhoneticFirstName", "");
@@ -568,20 +549,16 @@ function CheckAndSetCardValues(cardprope
   // set the birth day, month, and year properties
   cardproperty.setProperty("BirthDay", birthDay);
   cardproperty.setProperty("BirthMonth", birthMonth);
   cardproperty.setProperty("BirthYear", birthYear);
 
   var popup = document.getElementById("PreferMailFormatPopup");
   if (popup)
     cardproperty.setProperty("PreferMailFormat", popup.value);
-    
-  var allowRemoteContentEl = document.getElementById("allowRemoteContent");
-  if (allowRemoteContentEl)
-    cardproperty.setProperty("AllowRemoteContent", allowRemoteContentEl.checked);
 
   var preferDisplayNameEl = document.getElementById("preferDisplayName");
   if (preferDisplayNameEl)
     cardproperty.setProperty("PreferDisplayName", preferDisplayNameEl.checked);
 
   // set phonetic fields if exist
   try {
     cardproperty.setProperty("PhoneticFirstName", doc.getElementById("PhoneticFirstName").value);
--- a/mail/components/addrbook/content/abCardOverlay.xul
+++ b/mail/components/addrbook/content/abCardOverlay.xul
@@ -178,20 +178,16 @@
           <menulist id="PreferMailFormatPopup">
             <menupopup>
               <!-- 0,1,2 come from nsIAbPreferMailFormat in nsIAbCard.idl -->
               <menuitem value="0" label="&Unknown.label;"/>
               <menuitem value="1" label="&PlainText.label;"/>
               <menuitem value="2" label="&HTML.label;"/>
             </menupopup>
           </menulist>
-
-          <checkbox id="allowRemoteContent" label="&allowRemoteContent1.label;"
-                    accesskey="&allowRemoteContent1.accesskey;"
-                    tooltiptext="&allowRemoteContent1.tooltip;"/>
         </hbox>
       </vbox> <!-- End of Name Tab -->
 
       <!-- ** Home Address Tab ** -->
       <vbox id="abHomeTab" >
         <hbox align="center">
           <spacer flex="1"/>
           <label control="HomeAddress" value="&HomeAddress.label;"
--- a/mail/locales/en-US/chrome/messenger/addressbook/abCardOverlay.dtd
+++ b/mail/locales/en-US/chrome/messenger/addressbook/abCardOverlay.dtd
@@ -42,24 +42,16 @@
 <!ENTITY SecondEmail.accesskey          "i">
 <!ENTITY PreferMailFormat.label         "Prefers to receive messages formatted as:">
 <!ENTITY PreferMailFormat.accesskey     "v">
 <!ENTITY PlainText.label                "Plain Text">
 <!ENTITY HTML.label                     "HTML">
 <!ENTITY Unknown.label                  "Unknown">
 <!ENTITY chatName.label                 "Chat Name:">
 
-<!ENTITY allowRemoteContent1.label      "Allow remote content.">
-<!ENTITY allowRemoteContent1.accesskey  "r">
-<!ENTITY allowRemoteContent1.tooltip    "In HTML messages it is possible to
-embed content from remote sources. Opening such a message will open a
-connection to this external source. This may allow tracking of the
-message being read. Checking this box will allow such external embedded
-content in HTML messages from this contact.">
-
 <!ENTITY WorkPhone.label                "Work:">
 <!ENTITY WorkPhone.accesskey            "k">
 <!ENTITY HomePhone.label                "Home:">
 <!ENTITY HomePhone.accesskey            "m">
 <!ENTITY FaxNumber.label                "Fax:">
 <!ENTITY FaxNumber.accesskey            "x">
 <!ENTITY PagerNumber.label              "Pager:">
 <!ENTITY PagerNumber.accesskey          "g">
--- a/mail/locales/en-US/chrome/messenger/messenger.dtd
+++ b/mail/locales/en-US/chrome/messenger/messenger.dtd
@@ -558,18 +558,16 @@
 
 <!-- Toolbar Button Popup -->
 <!ENTITY buttonMenuForwardAsInline.label "Forward Inline">
 <!ENTITY buttonMenuForwardAsAttachment.label "Forward As Attachment">
 
 <!-- Remote Content Button Popup -->
 <!ENTITY remoteContentOptionsAllowForMsg.label "Show remote content in this message">
 <!ENTITY remoteContentOptionsAllowForMsg.accesskey "S">
-<!ENTITY remoteContentOptionAllowForAddress.label "Show remote content from this sender">
-<!ENTITY remoteContentOptionAllowForAddress.accesskey "f">
 <!ENTITY editRemoteContentSettings.label "Edit remote content options…">
 <!ENTITY editRemoteContentSettings.accesskey "E">
 <!ENTITY editRemoteContentSettingsUnix.label "Edit remote content preferences…">
 <!ENTITY editRemoteContentSettingsUnix.accesskey "E">
 
 <!-- Phishing Button Popup -->
 <!ENTITY phishingOptionIgnore.label "Ignore warning for this message">
 <!ENTITY phishingOptionIgnore.accesskey "n">
--- a/mailnews/addrbook/public/nsIAbCard.idl
+++ b/mailnews/addrbook/public/nsIAbCard.idl
@@ -52,18 +52,16 @@ interface nsIAbPreferMailFormat {
  *   - BirthYear, BirthMonth, BirthDay
  * - WebPage1 (work), WebPage2 (home)
  * - Custom1, Custom2, Custom3, Custom4
  * - Notes
  * - Integral properties:
  *   - LastModifiedDate
  *   - PopularityIndex
  *   - PreferMailFormat (see nsIAbPreferMailFormat)
- * - Boolean properties:
- *   - AllowRemoteContent
  * - Photo properties:
  *   - PhotoName
  *   - PhotoType
  *   - PhotoURI
  *
  * The contract id for the standard implementation is
  * <tt>\@mozilla.org/addressbook/cardproperty;1</tt>.
  */
@@ -292,17 +290,16 @@ interface nsIAbCard : nsIAbItem {
 #define kFirstNameProperty          "FirstName"
 #define kLastNameProperty           "LastName"
 #define kDisplayNameProperty        "DisplayName"
 #define kNicknameProperty           "NickName"
 #define kPriEmailProperty           "PrimaryEmail"
 #define kPreferMailFormatProperty   "PreferMailFormat"
 #define kLastModifiedDateProperty   "LastModifiedDate"
 #define kPopularityIndexProperty    "PopularityIndex"
-#define kAllowRemoteContentProperty "AllowRemoteContent"
 
 #define kPhoneticFirstNameProperty  "PhoneticFirstName"
 #define kPhoneticLastNameProperty   "PhoneticLastName"
 #define kSpouseNameProperty         "SpouseName"
 #define kFamilyNameProperty         "FamilyName"
 #define k2ndEmailProperty           "SecondEmail"
 
 #define kHomeAddressProperty        "HomeAddress"
--- a/mailnews/addrbook/public/nsIAddrDatabase.idl
+++ b/mailnews/addrbook/public/nsIAddrDatabase.idl
@@ -43,17 +43,17 @@ interface nsISimpleEnumerator;
 [scriptable, uuid(20d4c6c3-0460-403e-aa9c-813654641566)]
 interface nsAddrDBCommitType 
 {
   const long kLargeCommit = 1;
   const long kSessionCommit = 2;
   const long kCompressCommit = 3;
 };
 
-[scriptable, uuid(a71d3d0d-5605-4dd9-8ac1-b258cc3bda93)]
+[scriptable, uuid(c54973e4-d251-4b93-a0d0-81a616225061)]
 interface nsIAddrDatabase : nsIAddrDBAnnouncer {
 
   /**
    * Path to the address book database that this instance represents.
    */
   attribute nsIFile dbPath;
   nsIAddrDatabase open(in nsIFile dbFile, in boolean create, in boolean upgrading);
              
@@ -253,17 +253,16 @@ interface nsIAddrDatabase : nsIAddrDBAnn
   [noscript] void addBirthDay(in nsIMdbRow row, in string value);
   [noscript] void addCustom1(in nsIMdbRow row, in string value);
   [noscript] void addCustom2(in nsIMdbRow row, in string value);
   [noscript] void addCustom3(in nsIMdbRow row, in string value);
   [noscript] void addCustom4(in nsIMdbRow row, in string value);
   [noscript] void addNotes(in nsIMdbRow row, in string value);
   [noscript] void addPreferMailFormat(in nsIMdbRow row, in unsigned long value);
   [noscript] void addPopularityIndex(in nsIMdbRow row, in unsigned long value);
-  [noscript] void addAllowRemoteContent(in nsIMdbRow row, in boolean value);
 
   [noscript] void addListName(in nsIMdbRow row, in string value);
   [noscript] void addListNickName(in nsIMdbRow row, in string value);
   [noscript] void addListDescription(in nsIMdbRow row, in string value);
   [noscript] void addListDirNode(in nsIMdbRow listRow);
 
   /**
    * use for getting and setting generic string attributes
--- a/mailnews/addrbook/src/nsAbCardProperty.cpp
+++ b/mailnews/addrbook/src/nsAbCardProperty.cpp
@@ -107,17 +107,16 @@ static const AppendItem CHAT_ATTRS_ARRAY
 nsAbCardProperty::nsAbCardProperty()
   : m_IsMailList(false)
 {
   // Initialize some default properties
   SetPropertyAsUint32(kPreferMailFormatProperty, nsIAbPreferMailFormat::unknown);
   SetPropertyAsUint32(kPopularityIndexProperty, 0);
   // Uninitialized...
   SetPropertyAsUint32(kLastModifiedDateProperty, 0);
-  SetPropertyAsBool(kAllowRemoteContentProperty, false);
 }
 
 nsAbCardProperty::~nsAbCardProperty(void)
 {
 }
 
 NS_IMPL_ISUPPORTS(nsAbCardProperty, nsIAbCard, nsIAbItem)
 
--- a/mailnews/addrbook/src/nsAddrDatabase.cpp
+++ b/mailnews/addrbook/src/nsAddrDatabase.cpp
@@ -122,17 +122,16 @@ nsAddrDatabase::nsAddrDatabase()
       m_Custom1ColumnToken(0),
       m_Custom2ColumnToken(0),
       m_Custom3ColumnToken(0),
       m_Custom4ColumnToken(0),
       m_NotesColumnToken(0),
       m_LastModDateColumnToken(0),
       m_MailFormatColumnToken(0),
       m_PopularityIndexColumnToken(0),
-      m_AllowRemoteContentColumnToken(0),
       m_AddressCharSetColumnToken(0),
       m_LastRecordKey(0),
       m_dbDirectory(nullptr)
 {
 }
 
 nsAddrDatabase::~nsAddrDatabase()
 {
@@ -1057,17 +1056,16 @@ nsresult nsAddrDatabase::InitMDBInfo()
       m_mdbStore->StringToToken(m_mdbEnv,  kDisplayNameProperty, &m_DisplayNameColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kNicknameProperty, &m_NickNameColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kPriEmailProperty, &m_PriEmailColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kLowerPriEmailColumn, &m_LowerPriEmailColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  k2ndEmailProperty, &m_2ndEmailColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kLower2ndEmailColumn, &m_Lower2ndEmailColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kPreferMailFormatProperty, &m_MailFormatColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kPopularityIndexProperty, &m_PopularityIndexColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kAllowRemoteContentProperty, &m_AllowRemoteContentColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kWorkPhoneProperty, &m_WorkPhoneColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kHomePhoneProperty, &m_HomePhoneColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kFaxProperty, &m_FaxColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kPagerProperty, &m_PagerColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kCellularProperty, &m_CellularColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kWorkPhoneTypeProperty, &m_WorkPhoneTypeColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kHomePhoneTypeProperty, &m_HomePhoneTypeColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kFaxTypeProperty, &m_FaxTypeColumnToken);
--- a/mailnews/addrbook/src/nsAddrDatabase.h
+++ b/mailnews/addrbook/src/nsAddrDatabase.h
@@ -93,19 +93,16 @@ public:
   NS_IMETHOD Add2ndEmail(nsIMdbRow * row, const char * value) MOZ_OVERRIDE;
 
   NS_IMETHOD AddPreferMailFormat(nsIMdbRow * row, uint32_t value) MOZ_OVERRIDE
   { return AddIntColumn(row, m_MailFormatColumnToken, value); }
 
   NS_IMETHOD AddPopularityIndex(nsIMdbRow * row, uint32_t value) MOZ_OVERRIDE
   { return AddIntColumn(row, m_PopularityIndexColumnToken, value); }
 
-  NS_IMETHOD AddAllowRemoteContent(nsIMdbRow * row, bool value) MOZ_OVERRIDE
-  { return AddBoolColumn(row, m_AllowRemoteContentColumnToken, value); }
-
   NS_IMETHOD AddWorkPhone(nsIMdbRow * row, const char * value) MOZ_OVERRIDE
   { return AddCharStringColumn(row, m_WorkPhoneColumnToken, value); }
 
   NS_IMETHOD AddHomePhone(nsIMdbRow * row, const char * value) MOZ_OVERRIDE
   { return AddCharStringColumn(row, m_HomePhoneColumnToken, value); }
 
   NS_IMETHOD AddFaxNumber(nsIMdbRow * row, const char * value) MOZ_OVERRIDE
   { return AddCharStringColumn(row, m_FaxColumnToken, value); }
@@ -407,17 +404,16 @@ protected:
   mdb_token      m_NotesColumnToken;
   mdb_token      m_LastModDateColumnToken;
   mdb_token      m_RecordKeyColumnToken;
   mdb_token      m_LowerPriEmailColumnToken;
   mdb_token      m_Lower2ndEmailColumnToken;
 
   mdb_token      m_MailFormatColumnToken;
   mdb_token     m_PopularityIndexColumnToken;
-  mdb_token     m_AllowRemoteContentColumnToken;
 
   mdb_token      m_AddressCharSetColumnToken;
   mdb_token      m_LastRecordKeyColumnToken;
 
   mdb_token      m_ListNameColumnToken;
   mdb_token      m_ListNickNameColumnToken;
   mdb_token      m_ListDescriptionColumnToken;
   mdb_token      m_ListTotalColumnToken;
new file mode 100644
--- /dev/null
+++ b/mailnews/base/test/unit/data/remoteContent.mab
@@ -0,0 +1,61 @@
+// <!-- <mdb:mork:z v="1.4"/> -->
+< <(a=c)> // (f=iso-8859-1)
+  (B8=Notes)(B9=LastModifiedDate)(BA=RecordKey)(BB=AddrCharSet)
+  (BC=LastRecordKey)(BD=ns:addrbk:db:table:kind:pab)(BE=ListName)
+  (BF=ListNickName)(C0=ListDescription)(C1=ListTotalAddresses)
+  (C2=LowercaseListName)(C3=ns:addrbk:db:table:kind:deleted)(C4=_Yahoo)
+  (C5=_MSN)(C6=_GoogleTalk)(C7=_Skype)(C8=_IRC)(C9=_JabberId)
+  (CA=PreferDisplayName)(CB=PhotoURI)(CC=PhotoType)(CD=PhotoName)
+  (CE=DbRowID)(CF=_QQ)(D0=_ICQ)(80=ns:addrbk:db:row:scope:card:all)
+  (81=ns:addrbk:db:row:scope:list:all)
+  (82=ns:addrbk:db:row:scope:data:all)(83=FirstName)(84=LastName)
+  (85=PhoneticFirstName)(86=PhoneticLastName)(87=DisplayName)
+  (88=NickName)(89=PrimaryEmail)(8A=LowercasePrimaryEmail)
+  (8B=SecondEmail)(8C=LowercaseSecondEmail)(8D=PreferMailFormat)
+  (8E=PopularityIndex)(8F=AllowRemoteContent)(90=WorkPhone)(91=HomePhone)
+  (92=FaxNumber)(93=PagerNumber)(94=CellularNumber)(95=WorkPhoneType)
+  (96=HomePhoneType)(97=FaxNumberType)(98=PagerNumberType)
+  (99=CellularNumberType)(9A=HomeAddress)(9B=HomeAddress2)(9C=HomeCity)
+  (9D=HomeState)(9E=HomeZipCode)(9F=HomeCountry)(A0=WorkAddress)
+  (A1=WorkAddress2)(A2=WorkCity)(A3=WorkState)(A4=WorkZipCode)
+  (A5=WorkCountry)(A6=JobTitle)(A7=Department)(A8=Company)
+  (A9=_AimScreenName)(AA=AnniversaryYear)(AB=AnniversaryMonth)
+  (AC=AnniversaryDay)(AD=SpouseName)(AE=FamilyName)(AF=WebPage1)
+  (B0=WebPage2)(B1=BirthYear)(B2=BirthMonth)(B3=BirthDay)(B4=Custom1)
+  (B5=Custom2)(B6=Custom3)(B7=Custom4)>
+
+<(86=2)(81=)(80=0)(82=1)(83=no@test.invalid)(84=generic)(85
+    =yes@test.invalid)>
+{1:^80 {(k^BD:c)(s=9)} 
+  [1:^82(^BC=2)]
+  [1(^87=)(^86=)(^C4=)(^A2=)(^AF=)(^C5=)(^C6=)(^B3=)(^A8=)(^9B=)(^B4=)
+    (^C7=)(^A7=)(^A5=)(^A6=)(^A4=)(^C8=)(^85=)(^B1=)(^8E=0)(^C9=)(^A1=)
+    (^A3=)(^B8=)(^8D=0)(^9F=)(^B9=0)(^83=)(^A9=)(^CA=1)(^84=)(^93=)
+    (^CB=)(^B7=)(^9E=)(^89^83)(^8F=0)(^B0=)(^CC^84)(^90=)(^CD=)(^8B=)
+    (^94=)(^91=)(^CE=1)(^B2=)(^CF=)(^9C=)(^9D=)(^92=)(^B5=)(^A0=)(^9A=)
+    (^88=)(^D0=)(^B6=)(^8A^83)(^BA=1)]
+  [2(^87=)(^86=)(^C4=)(^A2=)(^AF=)(^C5=)(^C6=)(^B3=)(^A8=)(^9B=)(^B4=)
+    (^C7=)(^A7=)(^A5=)(^A6=)(^A4=)(^C8=)(^85=)(^B1=)(^8E=0)(^C9=)(^A1=)
+    (^A3=)(^B8=)(^8D=0)(^9F=)(^B9=0)(^83=)(^A9=)(^CA=1)(^84=)(^93=)
+    (^CB=)(^B7=)(^9E=)(^89^85)(^8F=0)(^B0=)(^CC^84)(^90=)(^CD=)(^8B=)
+    (^94=)(^91=)(^CE=2)(^B2=)(^CF=)(^9C=)(^9D=)(^92=)(^B5=)(^A0=)(^9A=)
+    (^88=)(^D0=)(^B6=)(^8A^85)(^BA=2)]}
+
+@$${2{@
+<(87=1397303325)>[-2:^80(^87=)(^86=)(^C4=)(^A2=)(^AF=)(^C5=)(^C6=)
+    (^B3=)(^A8=)(^9B=)(^B4=)(^C7=)(^A7=)(^A5=)(^A6=)(^A4=)(^C8=)(^85=)
+    (^B1=)(^8E=0)(^C9=)(^A1=)(^A3=)(^B8=)(^8D=0)(^9F=)(^B9^87)(^83=)
+    (^A9=)(^CA=1)(^84=)(^93=)(^CB=)(^B7=)(^9E=)(^89^85)(^8F=1)(^B0=)
+    (^CC^84)(^90=)(^CD=)(^8B=)(^94=)(^91=)(^CE=2)(^B2=)(^CF=)(^9C=)
+    (^9D=)(^92=)(^B5=)(^A0=)(^9A=)(^88=)(^D0=)(^B6=)(^8A^85)(^BA=2)]
+@$$}2}@
+
+@$${4{@
+<(88=1397383824)(89=yes2@test.invalid)>
+[-2:^80(^87=)(^86=)(^C4=)(^A2=)(^AF=)(^C5=)(^C6=)(^B3=)(^A8=)(^9B=)
+    (^B4=)(^C7=)(^A7=)(^A5=)(^A6=)(^A4=)(^C8=)(^85=)(^B1=)(^8E=0)(^C9=)
+    (^A1=)(^A3=)(^B8=)(^8D=0)(^9F=)(^B9^88)(^83=)(^A9=)(^CA=1)(^84=)
+    (^93=)(^CB=)(^B7=)(^9E=)(^89^85)(^8F=1)(^B0=)(^CC^84)(^90=)(^CD=)
+    (^8B^89)(^94=)(^91=)(^CE=2)(^B2=)(^CF=)(^9C=)(^9D=)(^92=)(^B5=)
+    (^A0=)(^9A=)(^88=)(^D0=)(^B6=)(^8A^85)(^BA=2)]
+@$$}4}@
--- a/mailnews/base/test/unit/test_accountMigration.js
+++ b/mailnews/base/test/unit/test_accountMigration.js
@@ -1,33 +1,55 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * This tests that we don't try to reset the mail.server.server<n>.authMethod
- * preference every time we run the migration code.
+ * preference every time we run the migration code, and other migration stuff
  */
 
+// make xpcshell-tests TEST_PATH=mailnews/base/test/unit/test_accountMigration.js
+
 Components.utils.import("resource:///modules/mailnewsMigrator.js");
 
+load("../../../resources/abSetup.js");
+
 function run_test() {
   // Set up some basic accounts with limited prefs - enough to satisfy the
   // migrator.
   Services.prefs.setCharPref("mail.account.account1.server", "server1");
   Services.prefs.setCharPref("mail.account.account2.server", "server2");
 
   // Server1 has nothing set.
 
   // Server2 has useSecAuth set to true, auth_login unset
   Services.prefs.setBoolPref("mail.server.server2.useSecAuth", true);
 
   Services.prefs.setCharPref("mail.accountmanager.accounts",
                              "account1,account2");
 
+  let testAB = do_get_file("data/remoteContent.mab");
+
+  // Copy the file to the profile directory for a PAB.
+  testAB.copyTo(do_get_profile(), kPABData.fileName);
+
+  let uriAllowed = Services.io.newURI("mailto:yes@test.invalid", null, null);
+  let uriAllowed2 = Services.io.newURI("mailto:yes2@test.invalid", null, null);
+  let uriDisallowed = Services.io.newURI("mailto:no@test.invalid", null, null);
+
+  // Check that this email that according to the ab data has (had!)
+  // remote content premissions, has no premissions pre migration.
+  do_check_eq(Services.perms.testPermission(uriAllowed, "image"),
+              Services.perms.UNKNOWN_ACTION);
+  do_check_eq(Services.perms.testPermission(uriAllowed2, "image"),
+              Services.perms.UNKNOWN_ACTION);
+  do_check_eq(Services.perms.testPermission(uriDisallowed, "image"),
+              Services.perms.UNKNOWN_ACTION);
+
   // Now migrate the prefs.
   migrateMailnews();
 
   // Check what has been set.
   do_check_false(Services.prefs.prefHasUserValue("mail.server.server1.authMethod"));
   do_check_true(Services.prefs.prefHasUserValue("mail.server.server2.authMethod"));
   do_check_eq(Services.prefs.getIntPref("mail.server.server2.authMethod"),
               Ci.nsMsgAuthMethod.secure);
@@ -50,16 +72,26 @@ function run_test() {
 
   Services.prefs.setCharPref("mail.smtpservers", "smtp1,smtp2");
 
   // smtp1 has nothing set.
 
   // smtp2 has useSecAuth set to true, auth_method unset
   Services.prefs.setBoolPref("mail.smtpserver.smtp2.useSecAuth", true);
 
+  // Migration should now have added permissions for the address that had them
+  // and not for the one that didn't have them.
+  do_check_true(Services.prefs.getIntPref("mail.ab_remote_content.migrated") > 0);
+  do_check_eq(Services.perms.testPermission(uriAllowed, "image"),
+              Services.perms.ALLOW_ACTION);
+  do_check_eq(Services.perms.testPermission(uriAllowed2, "image"),
+              Services.perms.ALLOW_ACTION);
+  do_check_eq(Services.perms.testPermission(uriDisallowed, "image"),
+              Services.perms.UNKNOWN_ACTION);
+
   // Now migrate the prefs
   migrateMailnews();
 
   do_check_false(Services.prefs.prefHasUserValue("mail.smtpserver.smtp1.authMethod"));
   do_check_true(Services.prefs.prefHasUserValue("mail.smtpserver.smtp2.authMethod"));
   do_check_eq(Services.prefs.getIntPref("mail.smtpserver.smtp2.authMethod"),
               Ci.nsMsgAuthMethod.secure);
 
--- a/mailnews/base/util/mailnewsMigrator.js
+++ b/mailnews/base/util/mailnewsMigrator.js
@@ -5,29 +5,35 @@
 /**
  * Migrate profile (prefs and other files) from older versions of Mailnews to
  * current.
  * This should be run at startup. It migrates as needed: each migration
  * function should be written to be a no-op when the value is already migrated
  * or was never used in the old version.
  */
 
-var EXPORTED_SYMBOLS = [ "migrateMailnews" ];
+const EXPORTED_SYMBOLS = [ "migrateMailnews" ];
 
 Components.utils.import("resource:///modules/errUtils.js");
 Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource:///modules/mailServices.js");
 const Ci = Components.interfaces;
 const kServerPrefVersion = 1;
 const kSmtpPrefVersion = 1;
+const kABRemoteContentPrefVersion = 1;
 
 function migrateMailnews()
 {
   try {
     MigrateServerAuthPref();
   } catch (e) { logException(e); }
+
+  try {
+    MigrateABRemoteContentSettings();
+  } catch (e) { logException(e); }
 }
 
 /**
  * Migrates from pref useSecAuth to pref authMethod
  */
 function MigrateServerAuthPref()
 {
   try {
@@ -99,8 +105,58 @@ function MigrateServerAuthPref()
           auth_method ? (useSecAuth ?
                             Ci.nsMsgAuthMethod.secure :
                             Ci.nsMsgAuthMethod.passwordCleartext) :
                         Ci.nsMsgAuthMethod.none);
       Services.prefs.setIntPref(server + "migrated", kSmtpPrefVersion);
     }
   } catch(e) { logException(e); }
 }
+
+/**
+ * The address book used to contain information about wheather to allow remote
+ * content for a given contact. Now we use the permission manager for that.
+ * Do a one-time migration for it.
+ */
+function MigrateABRemoteContentSettings()
+{
+  if (Services.prefs.prefHasUserValue("mail.ab_remote_content.migrated"))
+    return;
+
+  // Search through all of our local address books looking for a match.
+  let enumerator = MailServices.ab.directories;
+  while (enumerator.hasMoreElements())
+  {
+    let migrateAddress = function(aEmail) {
+      let uri = Services.io.newURI("mailto:" + aEmail, null, null);
+      Services.perms.add(uri, "image", Services.perms.ALLOW_ACTION);
+    }
+
+    let addrbook = enumerator.getNext()
+      .QueryInterface(Components.interfaces.nsIAbDirectory);
+    try {
+      // If it's a read-only book, don't try to find a card as we we could never
+      // have set the AllowRemoteContent property.
+      if (addrbook.readOnly)
+        continue;
+
+      let childCards = addrbook.childCards;
+      while (childCards.hasMoreElements())
+      {
+        let card = childCards.getNext()
+                             .QueryInterface(Components.interfaces.nsIAbCard);
+
+        if (card.getProperty("AllowRemoteContent", false) == false)
+          continue; // not allowed for this contact
+
+        if (card.primaryEmail)
+          migrateAddress(card.primaryEmail);
+
+        if (card.getProperty("SecondEmail", ""))
+          migrateAddress(card.getProperty("SecondEmail", ""));
+      }
+    } catch (e) { logException(e); }
+  }
+
+  Services.prefs.setIntPref("mail.ab_remote_content.migrated",
+                            kABRemoteContentPrefVersion);
+}
+
--- a/mailnews/import/test/unit/resources/import_helper.js
+++ b/mailnews/import/test/unit/resources/import_helper.js
@@ -131,18 +131,17 @@ function AbImportHelper(aFile, aModuleSe
 {
   GenericImportHelper.call(this, "addressbook", aModuleSearchString, aFile);
 
   this.mAbName = aAbName;
   /* Attribute notes:  The attributes listed in the declaration below are
    * supported by all three text export/import types. PreferMailFormat is only
    * supported by LDIF.
    * The following are not supported: anniversaryYear, anniversaryMonth,
-   * anniversaryDay, popularityIndex, isMailList, mailListURI, lastModifiedDate,
-   * and allowRemoteContent
+   * anniversaryDay, popularityIndex, isMailList, mailListURI, lastModifiedDate.
    */
   var supportedAttributes =
     ["FirstName", "LastName", "DisplayName", "NickName", "PrimaryEmail",
      "SecondEmail", "WorkPhone", "HomePhone", "FaxNumber", "PagerNumber",
      "CellularNumber", "HomeAddress", "HomeAddress2", "HomeCity", "HomeState",
      "HomeZipCode", "HomeCountry", "WorkAddress", "WorkAddress2", "WorkCity",
      "WorkState", "WorkZipCode", "WorkCountry", "JobTitle", "Department",
      "Company", "BirthYear", "BirthMonth", "BirthDay", "WebPage1", "WebPage2",