Bug 413260 -- Refactor the Address Book (nsIAbCard refactors). r=Standard8, sr=dmose.
authorJoshua Cranmer <Pidgeot18@gmail.com>
Thu, 07 Aug 2008 08:45:06 -0400
changeset 65 b9967a04b9bd
parent 64 9d26fe956df7
child 66 9cbd14a19dfd
push id59
push userPidgeot18@gmail.com
push date2008-08-07 12:46 +0000
treeherdercomm-central@b9967a04b9bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersStandard8, dmose
bugs413260
Bug 413260 -- Refactor the Address Book (nsIAbCard refactors). r=Standard8, sr=dmose. This patch is pretty much guaranteed to bitrot anything dealing with the address book.
mail/base/content/mailWindowOverlay.js
mail/components/addrbook/content/abCardOverlay.js
mail/components/addrbook/content/abCardViewOverlay.js
mail/components/addrbook/content/addressbook.js
mailnews/addrbook/public/Makefile.in
mailnews/addrbook/public/nsIAbCard.idl
mailnews/addrbook/public/nsIAbDirectory.idl
mailnews/addrbook/public/nsIAbItem.idl
mailnews/addrbook/public/nsIAbMDBCard.idl
mailnews/addrbook/public/nsIAddrDatabase.idl
mailnews/addrbook/resources/content/abCardOverlay.js
mailnews/addrbook/resources/content/abCardViewOverlay.js
mailnews/addrbook/resources/content/abMailListDialog.js
mailnews/addrbook/resources/content/addressbook.js
mailnews/addrbook/src/nsAbAddressCollecter.cpp
mailnews/addrbook/src/nsAbAutoCompleteSearch.js
mailnews/addrbook/src/nsAbAutoCompleteSession.cpp
mailnews/addrbook/src/nsAbCardProperty.cpp
mailnews/addrbook/src/nsAbCardProperty.h
mailnews/addrbook/src/nsAbDirectoryQuery.cpp
mailnews/addrbook/src/nsAbLDAPAttributeMap.js
mailnews/addrbook/src/nsAbLDAPCard.cpp
mailnews/addrbook/src/nsAbLDAPCard.h
mailnews/addrbook/src/nsAbLDAPReplicationData.cpp
mailnews/addrbook/src/nsAbMDBCard.cpp
mailnews/addrbook/src/nsAbMDBCard.h
mailnews/addrbook/src/nsAbMDBDirProperty.cpp
mailnews/addrbook/src/nsAbMDBDirectory.cpp
mailnews/addrbook/src/nsAbManager.cpp
mailnews/addrbook/src/nsAbOSXCard.mm
mailnews/addrbook/src/nsAbOSXUtils.h
mailnews/addrbook/src/nsAbOSXUtils.mm
mailnews/addrbook/src/nsAbOutlookCard.cpp
mailnews/addrbook/src/nsAbOutlookDirectory.cpp
mailnews/addrbook/src/nsAbView.cpp
mailnews/addrbook/src/nsAddbookProtocolHandler.cpp
mailnews/addrbook/src/nsAddrDatabase.cpp
mailnews/addrbook/test/unit/test_basic_nsIAbCard.js
mailnews/addrbook/test/unit/test_collection.js
mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch1.js
mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch2.js
mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch3.js
mailnews/addrbook/test/unit/test_nsIAbCard.js
mailnews/base/resources/content/mailWindowOverlay.js
mailnews/base/resources/content/msgHdrViewOverlay.js
mailnews/base/src/nsMsgContentPolicy.cpp
mailnews/compose/src/nsMsgCompose.cpp
mailnews/extensions/palmsync/src/nsAbIPCCard.cpp
mailnews/extensions/palmsync/src/nsAbIPCCard.h
mailnews/extensions/palmsync/src/nsAbPalmSync.cpp
mailnews/extensions/palmsync/src/nsAbPalmSync.h
mailnews/import/src/nsImportFieldMap.cpp
--- a/mail/base/content/mailWindowOverlay.js
+++ b/mail/base/content/mailWindowOverlay.js
@@ -2561,17 +2561,17 @@ function allowRemoteContentForSender()
     if (addrbook instanceof Components.interfaces.nsIAbMDBDirectory)
       cardForEmailAddress = addrbook.cardForEmailAddress(authorEmailAddress);
   }
 
   var allowRemoteContent = false;
   if (cardForEmailAddress && addrbook instanceof Components.interfaces.nsIAbDirectory)
   {
     // set the property for remote content
-    cardForEmailAddress.allowRemoteContent = true;
+    cardForEmailAddress.setProperty("AllowRemoteContent", true);
     addrbook.modifyCard(cardForEmailAddress);
     allowRemoteContent = true;
   }
   else
   {
     var args = {primaryEmail:authorEmailAddress, displayName:names.value[0],
                 allowRemoteContent:true};
     // create a new card and set the property
--- a/mail/components/addrbook/content/abCardOverlay.js
+++ b/mail/components/addrbook/content/abCardOverlay.js
@@ -42,56 +42,56 @@ const kNonVcardFields =
 
 const kPhoneticFields =
         ["PhoneticLastName", "PhoneticLabel1", "PhoneticSpacer1",
          "PhoneticFirstName", "PhoneticLabel2", "PhoneticSpacer2"];
 
 // Item is |[dialogField, cardProperty]|.
 const kVcardFields =
         [ // Contact > Name
-         ["FirstName", "firstName"],
-         ["LastName", "lastName"],
-         ["DisplayName", "displayName"],
-         ["NickName", "nickName"],
+         ["FirstName", "FirstName"],
+         ["LastName", "LastName"],
+         ["DisplayName", "DisplayName"],
+         ["NickName", "NickName"],
           // Contact > Internet
-         ["PrimaryEmail", "primaryEmail"],
-         ["SecondEmail", "secondEmail"],
-         ["ScreenName", "aimScreenName"], // NB: AIM.
+         ["PrimaryEmail", "PrimaryEmail"],
+         ["SecondEmail", "SecondEmail"],
+         ["ScreenName", "_AimScreenName"], // NB: AIM.
           // Contact > Phones
-         ["WorkPhone", "workPhone"],
-         ["HomePhone", "homePhone"],
-         ["FaxNumber", "faxNumber"],
-         ["PagerNumber", "pagerNumber"],
-         ["CellularNumber", "cellularNumber"],
+         ["WorkPhone", "WorkPhone"],
+         ["HomePhone", "HomePhone"],
+         ["FaxNumber", "FaxNumber"],
+         ["PagerNumber", "PagerNumber"],
+         ["CellularNumber", "CellularNumber"],
           // Address > Home
-         ["HomeAddress", "homeAddress"],
-         ["HomeAddress2", "homeAddress2"],
-         ["HomeCity", "homeCity"],
-         ["HomeState", "homeState"],
-         ["HomeZipCode", "homeZipCode"],
-         ["HomeCountry", "homeCountry"],
-         ["WebPage2", "webPage2"],
+         ["HomeAddress", "HomeAddress"],
+         ["HomeAddress2", "HomeAddress2"],
+         ["HomeCity", "HomeCity"],
+         ["HomeState", "HomeState"],
+         ["HomeZipCode", "HomeZipCode"],
+         ["HomeCountry", "HomeCountry"],
+         ["WebPage2", "WebPage2"],
           // Address > Work
-         ["JobTitle", "jobTitle"],
-         ["Department", "department"],
-         ["Company", "company"],
-         ["WorkAddress", "workAddress"],
-         ["WorkAddress2", "workAddress2"],
-         ["WorkCity", "workCity"],
-         ["WorkState", "workState"],
-         ["WorkZipCode", "workZipCode"],
-         ["WorkCountry", "workCountry"],
-         ["WebPage1", "webPage1"],
+         ["JobTitle", "JobTitle"],
+         ["Department", "Department"],
+         ["Company", "Company"],
+         ["WorkAddress", "WorkAddress"],
+         ["WorkAddress2", "WorkAddress2"],
+         ["WorkCity", "WorkCity"],
+         ["WorkState", "WorkState"],
+         ["WorkZipCode", "WorkZipCode"],
+         ["WorkCountry", "WorkCountry"],
+         ["WebPage1", "WebPage1"],
           // Other > (custom)
-         ["Custom1", "custom1"],
-         ["Custom2", "custom2"],
-         ["Custom3", "custom3"],
-         ["Custom4", "custom4"],
+         ["Custom1", "Custom1"],
+         ["Custom2", "Custom2"],
+         ["Custom3", "Custom3"],
+         ["Custom4", "Custom4"],
           // Other > Notes
-         ["Notes", "notes"]];
+         ["Notes", "Notes"]];
 
 var gEditCard;
 var gOnSaveListeners = new Array();
 var gOkCallback = null;
 var gHideABPicker = false;
 
 function OnLoadNewCard()
 {
@@ -132,22 +132,21 @@ function OnLoadNewCard()
       gEditCard.card.displayName = window.arguments[0].displayName;
       // if we've got a display name, don't generate
       // a display name (and stomp on the existing display name)
       // when the user types a first or last name
       if (gEditCard.card.displayName.length)
         gEditCard.generateDisplayName = false;
     }
     if ("aimScreenName" in window.arguments[0])
-      gEditCard.card.aimScreenName = window.arguments[0].aimScreenName;
-    
-    if ("allowRemoteContent" in window.arguments[0]) {
-      gEditCard.card.allowRemoteContent = window.arguments[0].allowRemoteContent;
-      window.arguments[0].allowRemoteContent = false;
-    }
+      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 =
@@ -365,17 +364,17 @@ function InitEditCard()
 
 function NewCardOKButton()
 {
   if (gOkCallback)
   {
     if (!CheckAndSetCardValues(gEditCard.card, document, true))
       return false;  // don't close window
 
-    gOkCallback(gEditCard.card.convertToEscapedVCard());
+    gOkCallback(gEditCard.card.translateTo("vcard"));
     return true;  // close the window
   }
 
   var popup = document.getElementById('abPopup');
   if ( popup )
   {
     var uri = popup.getAttribute('value');
 
@@ -390,46 +389,49 @@ function NewCardOKButton()
       if (!CheckAndSetCardValues(gEditCard.card, document, true))
         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.
       gEditCard.card = GetDirectoryFromURI(uri).addCard(gEditCard.card);
       NotifySaveListeners();
-      if ("arguments" in window && window.arguments[0])
-        window.arguments[0].allowRemoteContent = gEditCard.card.allowRemoteContent;
+      if ("arguments" in window && window.arguments[0]) {
+        window.arguments[0].allowRemoteContent =
+          gEditCard.card.getProperty("AllowRemoteContent", false);
+      }
     }
   }
 
   return true;  // close the window
 }
 
 // Move the data from the cardproperty to the dialog
 function GetCardValues(cardproperty, doc)
 {
   if (!cardproperty)
     return;
 
-  for (var i = kVcardFields.length; i-- > 0; )
+  for (var i = kVcardFields.length; i-- > 0; ) {
     doc.getElementById(kVcardFields[i][0]).value =
-      cardproperty[kVcardFields[i][1]];
+      cardproperty.getProperty(kVcardFields[i][1], "");
+  }
 
   var popup = document.getElementById("PreferMailFormatPopup");
   if (popup)
-    popup.value = cardproperty.preferMailFormat;
+    popup.value = cardproperty.getProperty("PreferMailFormat", "");
     
   var allowRemoteContentEl = document.getElementById("allowRemoteContent");
   if (allowRemoteContentEl)
-    allowRemoteContentEl.checked = cardproperty.allowRemoteContent;
+    allowRemoteContentEl.checked = cardproperty.getProperty("AllowRemoteContent", false);
 
   // get phonetic fields if exist
   try {
-    doc.getElementById("PhoneticFirstName").value = cardproperty.phoneticFirstName;
-    doc.getElementById("PhoneticLastName").value = cardproperty.phoneticLastName;
+    doc.getElementById("PhoneticFirstName").value = cardproperty.getProperty("PhoneticFirstName", "");
+    doc.getElementById("PhoneticLastName").value = cardproperty.getProperty("PhoneticLastName", "");
   }
   catch (ex) {}
 }
 
 // when the ab card dialog is being loaded to show a vCard,
 // hide the fields which aren't supported
 // by vCard so the user does not try to edit them.
 function HideNonVcardFields()
@@ -446,31 +448,31 @@ function CheckAndSetCardValues(cardprope
   // If requested, check the required data presence.
   if (check && !CheckCardRequiredDataPresence(document))
     return false;
 
   if (!cardproperty)
     return true;
 
   for (var i = kVcardFields.length; i-- > 0; )
-    cardproperty[kVcardFields[i][1]] =
-      doc.getElementById(kVcardFields[i][0]).value;
+    cardproperty.setProperty(kVcardFields[i][1],
+      doc.getElementById(kVcardFields[i][0]).value);
 
   var popup = document.getElementById("PreferMailFormatPopup");
   if (popup)
-    cardproperty.preferMailFormat = popup.value;
+    cardproperty.setProperty("PreferMailFormat", popup.value);
     
   var allowRemoteContentEl = document.getElementById("allowRemoteContent");
   if (allowRemoteContentEl)
-    cardproperty.allowRemoteContent = allowRemoteContentEl.checked;
+    cardproperty.setProperty("AllowRemoteContent", allowRemoteContentEl.checked);
     
   // set phonetic fields if exist
   try {
-    cardproperty.phoneticFirstName = doc.getElementById("PhoneticFirstName").value;
-    cardproperty.phoneticLastName = doc.getElementById("PhoneticLastName").value;
+    cardproperty.setProperty("PhoneticFirstName", doc.getElementById("PhoneticFirstName").value);
+    cardproperty.setProperty("PhoneticLastName", doc.getElementById("PhoneticLastName").value);
   }
   catch (ex) {}
 
   return true;
 }
 
 function CleanUpWebPage(webPage)
 {
--- a/mail/components/addrbook/content/abCardViewOverlay.js
+++ b/mail/components/addrbook/content/abCardViewOverlay.js
@@ -186,19 +186,30 @@ function GetAddressesFromURI(uri)
   return addresses;
 }
 
 function GoIM()
 {
   LaunchUrl(top.cvData.cvAimPresence.getAttribute("url"));
 }
 
-function DisplayCardViewPane(card)
+function DisplayCardViewPane(realCard)
 {
-  var generatedName = card.generateName(gPrefs.getIntPref("mail.addr_book.lastnamefirst"));
+  var generatedName = realCard.generateName(gPrefs.getIntPref("mail.addr_book.lastnamefirst"));
+
+  // This will become neater when bug 312116 is fixed...
+  // (card.property instead of card.getProperty("Property"))
+  var card = { getProperty : function (prop) {
+                 return realCard.getProperty(prop, "");
+               },
+               primaryEmail : realCard.primaryEmail,
+               displayName : realCard.displayName,
+               isMailList : realCard.isMailList,
+               mailListURI : realCard.mailListURI
+  };
 
   var data = top.cvData;
   var visible;
 
   var titleString;
   if (generatedName == "")
     titleString = card.primaryEmail;  // if no generatedName, use email
   else
@@ -206,17 +217,17 @@ function DisplayCardViewPane(card)
 
   // set fields in card view pane
   if (card.isMailList)
     cvSetNode(data.CardTitle, gAddressBookBundle.getFormattedString("viewListTitle", [generatedName]));
   else
     cvSetNode(data.CardTitle, gAddressBookBundle.getFormattedString("viewCardTitle", [titleString]));
 
   // Contact section
-  cvSetNodeWithLabel(data.cvNickname, zNickname, card.nickName);
+  cvSetNodeWithLabel(data.cvNickname, zNickname, card.getProperty("NickName"));
 
   if (card.isMailList) {
     // email1, display name and screenname always hidden when a mailing list.
     cvSetVisible(data.cvDisplayName, false);
     cvSetVisible(data.cvEmail1Box, false);
     cvSetVisible(data.cvScreennameBox, false);
 
     visible = HandleLink(data.cvListName, zListName, card.displayName, data.cvListNameBox, "mailto:" + encodeURIComponent(GenerateAddressFromCard(card))) || visible;
@@ -225,122 +236,163 @@ function DisplayCardViewPane(card)
     // listname always hidden if not a mailing list
     cvSetVisible(data.cvListNameBox, false);
 
     cvSetNodeWithLabel(data.cvDisplayName, zDisplayName, card.displayName);
 
     visible = HandleLink(data.cvEmail1, zPrimaryEmail, card.primaryEmail, data.cvEmail1Box, "mailto:" + card.primaryEmail) || visible;
   }
 
-  var goimURL = "aim:goim?screenname=" + card.aimScreenName;
-  var hasScreenName = HandleLink(data.cvScreenname, zScreenName, card.aimScreenName, data.cvScreennameBox, goimURL);
+  var goimURL = "aim:goim?screenname=" + card.getProperty("_AimScreenName");
+  var hasScreenName = HandleLink(data.cvScreenname, zScreenName,
+                                 card.getProperty("_AimScreenName"),
+                                 data.cvScreennameBox, goimURL);
 
   data.cvAimPresence.removeAttribute("src");
   data.cvAimPresence.removeAttribute("url");
   data.cvAimPresence.setAttribute("width","0");
 
 #if 0
     // for now, disable the presence check since we don't really support this anymore but we may again in the future.
     // I'm leaving the code here for historical reference. See Bug #295726.
     data.cvAimPresence.setAttribute("src","http://big.oscar.aol.com:80/" + card.aimScreenName + "?on_url=http://ncmail.netscape.com/include/nc/images/online.gif&off_url=http://ncmail.netscape.com/include/nc/images/offline.gif");
     data.cvAimPresence.setAttribute("url", goimURL);
     data.cvAimPresence.setAttribute("width","16");
 #endif
 
-  visible = hasScreenName || visible;
-  visible = HandleLink(data.cvEmail2, zSecondaryEmail, card.secondEmail, data.cvEmail2Box, "mailto:" + card.secondEmail) || visible;
+   visible = hasScreenName || visible;
+   visible = HandleLink(data.cvEmail2, zSecondaryEmail,
+                        card.getProperty("SecondEmail"), data.cvEmail2Box,
+                        "mailto:" + card.getProperty("SecondEmail")) || visible;
 
-  // Home section
-  visible = cvSetNode(data.cvHomeAddress, card.homeAddress);
-  visible = cvSetNode(data.cvHomeAddress2, card.homeAddress2) || visible;
-  visible = cvSetCityStateZip(data.cvHomeCityStZip, card.homeCity, card.homeState, card.homeZipCode) || visible;
-  visible = cvSetNode(data.cvHomeCountry, card.homeCountry) || visible;
-        if (visible) {
-          var homeMapItUrl = CreateMapItURL(card.homeAddress, card.homeAddress2, card.homeCity, card.homeState, card.homeZipCode, card.homeCountry);
-          if (homeMapItUrl) {
-      cvSetVisible(data.cvbHomeMapItBox, true);
-            data.cvHomeMapIt.setAttribute('url', homeMapItUrl);
-          }
-          else {
-      cvSetVisible(data.cvbHomeMapItBox, false);
-          }
-        }
-        else {
+   // Home section
+   visible = cvSetNode(data.cvHomeAddress, card.getProperty("HomeAddress"));
+   visible = cvSetNode(data.cvHomeAddress2, card.getProperty("HomeAddress2")) ||
+             visible;
+   visible = cvSetCityStateZip(data.cvHomeCityStZip,
+                               card.getProperty("HomeCity"),
+                               card.getProperty("HomeState"),
+                               card.getProperty("HomeZipCode")) || visible;
+   visible = cvSetNode(data.cvHomeCountry, card.getProperty("HomeCountry")) ||
+             visible;
+   if (visible) {
+     var homeMapItUrl = CreateMapItURL(card.getProperty("HomeAddress"),
+                                       card.getProperty("HomeAddress2"),
+                                       card.getProperty("HomeCity"),
+                                       card.getProperty("HomeState"),
+                                       card.getProperty("HomeZipCode"),
+                                       card.getProperty("HomeCountry"));
+    if (homeMapItUrl) {
+       cvSetVisible(data.cvbHomeMapItBox, true);
+       data.cvHomeMapIt.setAttribute('url', homeMapItUrl);
+    } else {
+       cvSetVisible(data.cvbHomeMapItBox, false);
+    }
+  } else {
     cvSetVisible(data.cvbHomeMapItBox, false);
-        }
+  }
 
-  visible = HandleLink(data.cvHomeWebPage, "", card.webPage2, data.cvHomeWebPageBox, card.webPage2) || visible;
+  visible = HandleLink(data.cvHomeWebPage, "", card.getProperty("WebPage2"),
+                       data.cvHomeWebPageBox, card.getProperty("WebPage2")) ||
+            visible;
 
   cvSetVisible(data.cvhHome, visible);
   cvSetVisible(data.cvbHome, visible);
   if (card.isMailList) {
     // Description section
-    visible = cvSetNode(data.cvDescription, card.notes)
+    visible = cvSetNode(data.cvDescription, card.getProperty("Notes"))
     cvSetVisible(data.cvbDescription, visible);
 
     // Addresses section
     visible = cvAddAddressNodes(data.cvAddresses, card.mailListURI);
     cvSetVisible(data.cvbAddresses, visible);
 
     // Other section, not shown for mailing lists.
     cvSetVisible(data.cvbOther, false);
   }
   else {
     // Other section
-    visible = cvSetNodeWithLabel(data.cvCustom1, zCustom1, card.custom1);
-    visible = cvSetNodeWithLabel(data.cvCustom2, zCustom2, card.custom2) || visible;
-    visible = cvSetNodeWithLabel(data.cvCustom3, zCustom3, card.custom3) || visible;
-    visible = cvSetNodeWithLabel(data.cvCustom4, zCustom4, card.custom4) || visible;
-    visible = cvSetNode(data.cvNotes, card.notes) || visible;
+    visible = cvSetNodeWithLabel(data.cvCustom1, zCustom1,
+                                 card.getProperty("Custom1"));
+    visible = cvSetNodeWithLabel(data.cvCustom2, zCustom2,
+                                 card.getProperty("Custom2")) || visible;
+    visible = cvSetNodeWithLabel(data.cvCustom3, zCustom3,
+                                 card.getProperty("Custom3")) || visible;
+    visible = cvSetNodeWithLabel(data.cvCustom4, zCustom4,
+                                 card.getProperty("Custom4")) || visible;
+    visible = cvSetNode(data.cvNotes, card.getProperty("Notes")) || visible;
     visible = setBuddyIcon(card, data.cvBuddyIcon) || visible;
 
     cvSetVisible(data.cvhOther, visible);
     cvSetVisible(data.cvbOther, visible);
 
     // hide description section, not show for non-mailing lists
     cvSetVisible(data.cvbDescription, false);
 
     // hide addresses section, not show for non-mailing lists
     cvSetVisible(data.cvbAddresses, false);
   }
 
   // Phone section
-  visible = cvSetNodeWithLabel(data.cvPhWork, zWork, card.workPhone);
-  visible = cvSetNodeWithLabel(data.cvPhHome, zHome, card.homePhone) || visible;
-  visible = cvSetNodeWithLabel(data.cvPhFax, zFax, card.faxNumber) || visible;
-  visible = cvSetNodeWithLabel(data.cvPhCellular, zCellular, card.cellularNumber) || visible;
-  visible = cvSetNodeWithLabel(data.cvPhPager, zPager, card.pagerNumber) || visible;
+  visible = cvSetNodeWithLabel(data.cvPhWork, zWork,
+                               card.getProperty("WorkPhone"));
+  visible = cvSetNodeWithLabel(data.cvPhHome, zHome,
+                               card.getProperty("HomePhone")) || visible;
+  visible = cvSetNodeWithLabel(data.cvPhFax, zFax,
+                               card.getProperty("FaxNumber")) || visible;
+  visible = cvSetNodeWithLabel(data.cvPhCellular, zCellular,
+                               card.getProperty("CellularNumber")) || visible;
+  visible = cvSetNodeWithLabel(data.cvPhPager, zPager,
+                               card.getProperty("PagerNumber")) || visible;
   cvSetVisible(data.cvhPhone, visible);
   cvSetVisible(data.cvbPhone, visible);
   // Work section
-  visible = cvSetNode(data.cvJobTitle, card.jobTitle);
-  visible = cvSetNode(data.cvDepartment, card.department) || visible;
-  visible = cvSetNode(data.cvCompany, card.company) || visible;
+  visible = cvSetNode(data.cvJobTitle, card.getProperty("JobTitle"));
+  visible = cvSetNode(data.cvDepartment, card.getProperty("Department")) ||
+            visible;
+  visible = cvSetNode(data.cvCompany, card.getProperty("Company")) || visible;
 
-        var addressVisible = cvSetNode(data.cvWorkAddress, card.workAddress);
-  addressVisible = cvSetNode(data.cvWorkAddress2, card.workAddress2) || addressVisible;
-  addressVisible = cvSetCityStateZip(data.cvWorkCityStZip, card.workCity, card.workState, card.workZipCode) || addressVisible;
-  addressVisible = cvSetNode(data.cvWorkCountry, card.workCountry) || addressVisible;
+  var addressVisible = cvSetNode(data.cvWorkAddress,
+                                 card.getProperty("WorkAddress"));
+  addressVisible = cvSetNode(data.cvWorkAddress2,
+                             card.getProperty("WorkAddress2")) ||
+                   addressVisible;
+  addressVisible = cvSetCityStateZip(data.cvWorkCityStZip,
+                                     card.getProperty("WorkCity"),
+                                     card.getProperty("WorkState"),
+                                     card.getProperty("WorkZipCode")) ||
+                   addressVisible;
+  addressVisible = cvSetNode(data.cvWorkCountry,
+                             card.getProperty("WorkCountry")) || addressVisible;
 
         if (addressVisible) {
-          var workMapItUrl = CreateMapItURL(card.workAddress, card.workAddress2, card.workCity, card.workState, card.workZipCode, card.workCountry);
+          var workMapItUrl = CreateMapItURL(card.getProperty("WorkAddress"),
+                                            card.getProperty("WorkAddress2"),
+                                            card.getProperty("WorkCity"),
+                                            card.getProperty("WorkState"),
+                                            card.getProperty("WorkZipCode"),
+                                            card.getProperty("WorkCountry"));
           data.cvWorkMapIt.setAttribute('url', workMapItUrl);
           if (workMapItUrl) {
       cvSetVisible(data.cvbWorkMapItBox, true);
             data.cvWorkMapIt.setAttribute('url', workMapItUrl);
           }
           else {
       cvSetVisible(data.cvbWorkMapItBox, false);
           }
         }
         else {
     cvSetVisible(data.cvbWorkMapItBox, false);
         }
 
-        visible = HandleLink(data.cvWorkWebPage, "", card.webPage1, data.cvWorkWebPageBox, card.webPage1) || addressVisible || visible;
+        visible = HandleLink(data.cvWorkWebPage, "",
+                             card.getProperty("WebPage1"),
+                             data.cvWorkWebPageBox,
+                             card.getProperty("WebPage1")) || addressVisible ||
+                             visible;
 
   cvSetVisible(data.cvhWork, visible);
   cvSetVisible(data.cvbWork, visible);
 
   // make the card view box visible
   cvSetVisible(top.cvData.CardViewBox, true);
 }
 
@@ -353,17 +405,17 @@ function setBuddyIcon(card, buddyIcon)
         // lazily create these file urls, and keep them around
         var dirService = Components.classes["@mozilla.org/file/directory_service;1"]
             .getService(Components.interfaces.nsIProperties);
         var profileDir = dirService.get("ProfD", Components.interfaces.nsIFile);
         gProfileDirURL = gIOService.newFileURI(profileDir);
       }
 
       // if we did have a buddy icon on disk for this screenname, this would be the file url spec for it
-      var iconURLStr = gProfileDirURL.spec + "/NIM/" + myScreenName + "/picture/" + card.aimScreenName + ".gif";
+      var iconURLStr = gProfileDirURL.spec + "/NIM/" + myScreenName + "/picture/" + card.getProperty("_AimScreenName") + ".gif";
 
       // check if the file exists
       var file = gFileHandler.getFileFromURLSpec(iconURLStr);
 
       // check if the file exists
       // is this a perf hit?  (how expensive is stat()?)
       if (file.exists()) {
         buddyIcon.setAttribute("src", iconURLStr);
--- a/mail/components/addrbook/content/addressbook.js
+++ b/mail/components/addrbook/content/addressbook.js
@@ -352,18 +352,17 @@ function AbPrintCard()
 
 function AbPrintPreviewCard()
 {
   AbPrintCardInternal(true, Components.interfaces.nsIMsgPrintEngine.MNAB_PRINTPREVIEW_AB_CARD);
 }
 
 function CreatePrintCardUrl(card)
 {
-  var url = "data:application/xml;base64," + card.convertToBase64EncodedXML();
-  return url;
+  return "data:application/xml;base64," + card.translateTo("base64xml");
 }
 
 function AbPrintAddressBookInternal(doPrintPreview, msgType)
 {
   var uri = GetSelectedDirectory();
   if (!uri)
     return;
 
--- a/mailnews/addrbook/public/Makefile.in
+++ b/mailnews/addrbook/public/Makefile.in
@@ -43,19 +43,19 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= addrbook
 
 XPIDLSRCS	= \
 		nsIAbListener.idl \
 		nsIAbDirectory.idl \
+		nsIAbItem.idl \
 		nsIAbCard.idl \
 		nsIAbMDBDirectory.idl \
-		nsIAbMDBCard.idl \
 		nsIAddrDBAnnouncer.idl \
 		nsIAddrDBListener.idl \
 		nsIAddrDatabase.idl \
 		nsIAbManager.idl \
 		nsIAbAddressCollecter.idl \
 		nsIAddbookUrl.idl \
 		nsIAbDirFactory.idl	\
 		nsIAbDirFactoryService.idl	\
--- a/mailnews/addrbook/public/nsIAbCard.idl
+++ b/mailnews/addrbook/public/nsIAbCard.idl
@@ -15,164 +15,293 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *  Mark Banner <bugzilla@standard8.plus.com>
+ *  Joshua Cranmer <Pidgeot18@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
  
 #include "nsISupports.idl"
+#include "nsIAbItem.idl"
 
-interface nsIStringBundle;
+interface nsISimpleEnumerator;
+interface nsIVariant;
 
 [scriptable, uuid(97448252-F189-11d4-A422-001083003D0C)]
 interface nsIAbPreferMailFormat {
     const unsigned long unknown   = 0;
     const unsigned long plaintext = 1;
     const unsigned long html      = 2;
 };
 
-[scriptable, uuid(193d5026-7d1e-41b4-9fc3-c57d4a4937f3)]
-interface nsIAbCard : nsISupports {
-  // Card properties
+/**
+ * An interface representing an address book card.
+ *
+ * Fundamentally, it is a collection of properties. Modifying a property in
+ * some way on a card does not change the backend used to store the card; the
+ * directory is required to do make the changes here.
+ *
+ * The following are the core properties that are used:
+ * - Names:
+ *   - FirstName, LastName
+ *   - PhoneticFirstName, PhoneticLastName
+ *   - DisplayName, NickName
+ *   - SpouseName, FamilyName
+ * - PrimaryEmail, SecondEmail
+ * - Home Contact:
+ *   - HomeAddress, HomeAddress2, HomeCity, HomeState, HomeZipCode, HomeCountry
+ *   - HomePhone, HomePhoneType
+ * - Work contact. Same as home, but with `Work' instead of `Home'
+ * - Other Contact:
+ *   - FaxNumber, FaxNumberType
+ *   - PagerNumber, PagerNumberType
+ *   - CellularNumber, CellularNumberType
+ * - JobTitle, Department, Company
+ * - _AimScreenName
+ * - Dates:
+ *   - AnniversaryYear, AnniversaryMonth, AnniversaryDay
+ *   - BirthYear, BirthMonth, BirthDay
+ * - WebPage1 (work), WebPage2 (home)
+ * - Custom1, Custom2, Custom3, Custom4
+ * - Notes
+ * - Integral properties:
+ *   - LastModifiedDate
+ *   - PopularityIndex
+ *   - PreferMailFormat (see nsIAbPreferMailFormat)
+ * - Boolean properties:
+ *   - AllowRemoteContent
+ */
+[scriptable, uuid(f5646fba-3d20-4fdf-90fb-9f2ee9899dbb)]
+interface nsIAbCard : nsIAbItem {
+  /**
+   * A list of all the properties that this card has as an enumerator, whose
+   * members are all nsIProperty objects.
+   */
+  readonly attribute nsISimpleEnumerator properties;
+
+  /**
+   * Returns a property for the given name.
+   *
+   * @param name             The case-sensitive name of the property to get.
+   * @param defaultValue     The value to return if the property does not exist.
+   * @exception NS_ERROR_NOT_AVAILABLE if the named property does not exist.
+   * @exception NS_ERROR_CANNOT_CONVERT_DATA if the property cannot be converted
+   *                                         to the desired type.
+   */
+  nsIVariant getProperty(in AUTF8String name, in nsIVariant defaultValue);
+  /**
+   * @{
+   * Returns a property for the given name.
+   *
+   * These functions convert values in the same manner as the default
+   * implementation of nsIVariant. Of particular note is that boolean variables
+   * are converted to integers as in C/C++ (true is a non-zero value), so that
+   * false will be converted to a string of "0" and not "false."
+   *
+   * These functions are marked [noscript] since xpconnect performs automatic
+   * type conversion on nsIVariants such that they are not needed for scripts,
+   * only for C++ callers.
+   *
+   * @param name             The case-sensitive name of the property to get.
+   * @exception NS_ERROR_NOT_AVAILABLE if the named property does not exist.
+   * @exception NS_ERROR_CANNOT_CONVERT_DATA if the property cannot be converted
+   *                                         to the desired type.
+   */
+  [noscript] AString getPropertyAsAString(in string name);
+  [noscript] AUTF8String getPropertyAsAUTF8String(in string name);
+  [noscript] PRUint32 getPropertyAsUint32(in string name);
+  [noscript] boolean getPropertyAsBool(in string name);
+  /** @} */
+
+  /**
+   * @{
+   * Assigns the given to value to the property of the given name.
+   *
+   * Should the property exist, its value will be overwritten. An
+   * implementation may impose additional semantic constraints for certain
+   * properties. However, such constraints might not be checked by this method.
+   *
+   * These functions convert values in the same manner as the default
+   * implementation of nsIVariant.
+   * 
+   * @warning A value MUST be convertible to a string; if this convention is not
+   * followed, consumers of cards may fail unpredictably or return incorrect
+   * results.
+   *
+   * The non-variant functions are marked [noscript] since xpconnect uses
+   * magic with nsIVariant such that the other functions are not needed,
+   * although C++ does need them.
+   *
+   * @param name             The case-sensitive name of the property to set.
+   * @param value            The new value of the property.
+   */
+  void setProperty(in AUTF8String name, in nsIVariant value);
+  [noscript] void setPropertyAsAString(in string name, in AString value);
+  [noscript] void setPropertyAsAUTF8String(in string name, in AUTF8String value);
+  [noscript] void setPropertyAsUint32(in string name, in PRUint32 value);
+  [noscript] void setPropertyAsBool(in string name, in boolean value);
+  /** @} */
+
+  /**
+   * Deletes the property with the given name.
+   *
+   * Some properties may not be deleted. However, the implementation will not
+   * check this constraint at this method. If such a property is deleted, an
+   * error may be thrown when the card is modified at the database level.
+   *
+   * @param name             The case-sensitive name of the property to set.
+   */
+  void deleteProperty(in AUTF8String name);
+ 
+  /**
+   * @{
+   * These properties are shorthand for getProperty and setProperty.
+   */
   attribute AString firstName;
   attribute AString lastName;
-  attribute AString phoneticFirstName;
-  attribute AString phoneticLastName;
   attribute AString displayName;
-  attribute AString nickName;
   attribute AString primaryEmail;
-  attribute AString secondEmail;
-  attribute AString workPhone;
-  attribute AString homePhone;
-  attribute AString faxNumber;
-  attribute AString pagerNumber;
-  attribute AString cellularNumber;
-  attribute AString workPhoneType;
-  attribute AString homePhoneType;
-  attribute AString faxNumberType;
-  attribute AString pagerNumberType;
-  attribute AString cellularNumberType;
-  attribute AString homeAddress;
-  attribute AString homeAddress2;
-  attribute AString homeCity;
-  attribute AString homeState;
-  attribute AString homeZipCode;
-  attribute AString homeCountry;
-  attribute AString workAddress;
-  attribute AString workAddress2;
-  attribute AString workCity;
-  attribute AString workState;
-  attribute AString workZipCode;
-  attribute AString workCountry;
-  attribute AString jobTitle;
-  attribute AString department;
-  attribute AString company;
-  attribute AString aimScreenName;
-  attribute AString anniversaryYear;
-  attribute AString anniversaryMonth;
-  attribute AString anniversaryDay;
-  attribute AString spouseName;
-  attribute AString familyName;
-  attribute AString defaultAddress;
-  attribute AString category;
-  /**
-   * webPage1 is work web page
-   */
-  attribute AString webPage1;
-  /**
-   * webPage2 is home web page
-   */
-  attribute AString webPage2;
-  attribute AString birthYear;
-  attribute AString birthMonth;
-  attribute AString birthDay;
-  attribute AString custom1;
-  attribute AString custom2;
-  attribute AString custom3;
-  attribute AString custom4;
-  attribute AString notes;
-  attribute unsigned long lastModifiedDate;
-  /**
-   * Popularity Index is bumped every time e-mail is sent to this recipient
-   */
-  attribute unsigned long popularityIndex;
-  attribute unsigned long preferMailFormat;
-  attribute boolean isMailList;
-  /**
-   * If isMailList is true then mailListURI
-   * will contain the URI of the associated
-   * mail list
-   */
-  attribute string mailListURI;
-  /**
-   * allowRemoteContent to be displayed in HTML mail received from this contact
-   */
-  attribute boolean allowRemoteContent;
-
-  AString getCardValue(in string name);
-
-  void setCardValue(in string attrname, in AString value);
+  /** @} */
 
   /**
-   * This function will copy all values from one card to another.
-   *
-   * @param  srcCard  The source card to copy values from.
-   */
-  void copy(in nsIAbCard srcCard);
-
-  boolean equals(in nsIAbCard card);
-
-  string convertToBase64EncodedXML();
-  AString convertToXMLPrintData();
-  string convertToEscapedVCard();
-
-  /** 
-   * Generate a name from the card for display purposes. Using the firstName,
-   * lastName and the displayName. We allow the caller to cache the pref value,
-   * so we don't have to go to prefs every time.
-   *
-   * The format follows the "mail.addr_book.lastnamefirst" pref values:
+   * Translates a card into a specific format.
+   * The following types are supported:
+   * - base64xml
+   * - xml
+   * - vcard
    *
-   * 0 = generated name is displayName
-   * 1 = lastFirst, formatted following lastFirstFormat
-   * 2 = firstLast, formatted following firstLastFormat
-   *
-   * lastFirstFormat and firstLastFormat are defined in addressBook.properties.
-   *
-   * @param  aGenerateFormat The format to generate as per the above definition.
-   * @param  aBundle         An optional parameter that is a pointer to a string
-   *                         bundle that holds:
-   *           chrome://messenger/locale/addressbook/addressBook.properties
-   *                         If this bundle is not supplied, then the function
-   *                         will obtain the bundle itself. If cached by the
-   *                         caller and supplied to this function, then
-   *                         performance will be improved over many calls.
-   * @return                 A string containing the generated name.
+   * @param  aType          The type of item to translate the card into.
+   * @return                A string containing the translated card.
+   * @exception NS_ERROR_ILLEGAL_VALUE if we do not recognize the type.
    */
-  AString generateName(in long aGenerateFormat,
-                       [optional] in nsIStringBundle aBundle);
+  AUTF8String translateTo(in AUTF8String aType);
+
+  /**
+   * Translates a card from the specified format
+   */
+  //void translateFrom(in AUTF8String aType, in AUTF8String aData);
 
   /** 
    * Generate a phonetic name from the card, using the firstName and lastName
    * values.
    *
    * @param  aLastNameFirst  Set to True to put the last name before the first.
    * @return                 A string containing the generated phonetic name.
    */
   AString generatePhoneticName(in boolean aLastNameFirst);
+
+  /**
+   * This function will copy all values from one card to another.
+   *
+   * @param  srcCard         The source card to copy values from.
+   */
+  void copy(in nsIAbCard aSrcCard);
+
+  /**
+   * Returns true if this card is equal to the other card.
+   *
+   * The default implementation defines equal as this card pointing to the
+   * same object as @arg aCard; another implementation defines it as equality of
+   * properties and values.
+   *
+   * @warning The exact nature of equality is still undefined, and actual
+   *          results may not match theoretical results. Most notably, the code
+   *          <tt>a.equals(b) == b.equals(a)</tt> might not return true. In
+   *          particular, calling equals on cards from different address books
+   *          may return inaccurate results.
+   *          
+   *
+   * @return                 Equality, as defined above.
+   * @param  aCard           The card to compare against.
+   */
+  boolean equals(in nsIAbCard aCard);
+
+  // PROPERTIES TO BE DELETED AS PART OF REWRITE
+
+  attribute boolean isMailList;
+  /**
+   * If isMailList is true then mailListURI
+   * will contain the URI of the associated
+   * mail list
+   */
+  attribute string mailListURI;
 };
+
+%{C++
+// A nice list of properties for the benefit of C++ clients
+#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"
+#define kHomeAddress2Property       "HomeAddress2"
+#define kHomeCityProperty           "HomeCity"
+#define kHomeStateProperty          "HomeState"
+#define kHomeZipCodeProperty        "HomeZipCode"
+#define kHomeCountryProperty        "HomeCountry"
+#define kHomeWebPageProperty        "WebPage2"
+
+#define kWorkAddressProperty        "WorkAddress"
+#define kWorkAddress2Property       "WorkAddress2"
+#define kWorkCityProperty           "WorkCity"
+#define kWorkStateProperty          "WorkState"
+#define kWorkZipCodeProperty        "WorkZipCode"
+#define kWorkCountryProperty        "WorkCountry"
+#define kWorkWebPageProperty        "WebPage1"
+
+#define kHomePhoneProperty          "HomePhone"
+#define kHomePhoneTypeProperty      "HomePhoneType"
+#define kWorkPhoneProperty          "WorkPhone"
+#define kWorkPhoneTypeProperty      "WorkPhoneType"
+#define kFaxProperty                "FaxNumber"
+#define kFaxTypeProperty            "FaxNumberType"
+#define kPagerTypeProperty          "PagerNumberType"
+#define kPagerProperty              "PagerNumber"
+#define kCellularProperty           "CellularNumber"
+#define kCellularTypeProperty       "CellularNumberType"
+
+#define kJobTitleProperty           "JobTitle"
+#define kDepartmentProperty         "Department"
+#define kCompanyProperty            "Company"
+#define kScreenNameProperty         "_AimScreenName"
+#define kCustom1Property            "Custom1"
+#define kCustom2Property            "Custom2"
+#define kCustom3Property            "Custom3"
+#define kCustom4Property            "Custom4"
+#define kNotesProperty              "Notes"
+
+#define kAnniversaryYearProperty    "AnniversaryYear"
+#define kAnniversaryMonthProperty   "AnniversaryMonth"
+#define kAnniversaryDayProperty     "AnniversaryDay"
+#define kBirthYearProperty          "BirthYear"
+#define kBirthMonthProperty         "BirthMonth"
+#define kBirthDayProperty           "BirthDay"
+%}
--- a/mailnews/addrbook/public/nsIAbDirectory.idl
+++ b/mailnews/addrbook/public/nsIAbDirectory.idl
@@ -134,19 +134,22 @@ interface nsIAbDirectory : nsISupports {
   // NS_ERROR_NOT_AVAILABLE exception if the card
   // cannot be found.
   boolean hasCard(in nsIAbCard cards);
 
   // Check if directory contains directory
   boolean hasDirectory(in nsIAbDirectory dir);
 
   /**
-   * Adds a card to the database. card may be an abstract card.
+   * Adds a card to the database.
    *
-   * @return "Real" card (eg nsIAbMDBCard) that can be used for some
+   * This card does not need to be of the same type as the database, e.g., one
+   * can add an nsIAbLDAPCard to an nsIAbMDBDirectory.
+   *
+   * @return "Real" card (eg nsIAbLDAPCard) that can be used for some
    *         extra functions.
    */
   nsIAbCard addCard(in nsIAbCard card);
 
   /**
    * Modifies a card in the database to match that supplied.
    */
   void modifyCard(in nsIAbCard modifiedCard);
new file mode 100644
--- /dev/null
+++ b/mailnews/addrbook/public/nsIAbItem.idl
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2008
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mark Banner <bugzilla@standard8.plus.com>
+ *  Joshua Cranmer <Pidgeot18@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIMsgHeaderParser;
+interface nsIStringBundle;
+
+/**
+ * A containable item for address books.
+ */
+[scriptable, uuid(f7320616-3139-419b-a7c3-37441da3caf3)]
+interface nsIAbItem : nsISupports {
+  /**
+   * @{
+   * These constants reflect the possible values of the
+   * mail.addr_book.lastnamefirst preferences. They are intended to be used in
+   * generateName, defined below.
+   */
+   const unsigned long GENERATE_DISPLAY_NAME = 0;
+   const unsigned long GENERATE_LAST_FIRST_ORDER = 1;
+   const unsigned long GENERATE_FIRST_LAST_ORDER = 2;
+   /** @} */
+
+  /** 
+   * Generate a name from the item for display purposes.
+   *
+   * If this item is an nsIAbCard, then it will use the aGenerateFormat option
+   * to determine the string to return.
+   * If this item is not an nsIAbCard, then the aGenerateFormat option may be
+   * ignored, and the displayName of the item returned.
+   *
+   * @param  aGenerateFormat The format to generate as per the GENERATE_*
+   *                         constants above.
+   * @param  aBundle         An optional parameter that is a pointer to a string
+   *                         bundle that holds:
+   *           chrome://messenger/locale/addressbook/addressBook.properties
+   *                         If this bundle is not supplied, then the function
+   *                         will obtain the bundle itself. If cached by the
+   *                         caller and supplied to this function, then
+   *                         performance will be improved over many calls.
+   * @return                 A string containing the generated name.
+   */
+  AString generateName(in long aGenerateFormat,
+                       [optional] in nsIStringBundle aBundle);
+
+  /**
+   * Generate a formatted email address from the card, that can be used for
+   * sending emails.
+   *
+   * @param  aExpandList     If this card is a list, and this parameter is set
+   *                         to true, then the list will be expanded to include
+   *                         the emails of the cards within the list.
+   * @param  aGroupMailLists If this card (or the items within this card) is a
+   *                         list, and this is set to true, then the list will
+   *                         be expanded in the RFC 2822 group format
+   *                         "displayname : email1 ; email2 ; etc".
+   * @param  aHeaderParser   An optional parameter pointing to the
+   *                         nsIMsgHeaderParser service. If this is not supplied
+   *                         the function will obtain the service itself. If
+   *                         cached by the called and supplied to this function,
+   *                         then performance will be improved over many calls.
+   * @return                 A string containing a comma-separated list of
+   *                         formatted addresses.
+   */
+  //AString generateFormattedEmail(in boolean aExpandList,
+  //                               in boolean aAsGroupMailLists,
+  //                               [optional] in nsIMsgHeaderParser aHeaderParser);
+
+};
+
deleted file mode 100644
--- a/mailnews/addrbook/public/nsIAbMDBCard.idl
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Paul Sandoz <paul.sandoz@sun.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-
-#include "nsISupports.idl"
-
-interface nsIAddrDatabase;
-
-[scriptable, uuid(3ed862c5-7007-49fc-8834-094e1c71baab)]
-interface nsIAbMDBCard : nsISupports {
-	// used by the absync code
-	attribute unsigned long key;
-
-	// DB specific methods
-    attribute unsigned long dbTableID;
-    attribute unsigned long dbRowID;
-
-	void setAbDatabase(in nsIAddrDatabase database);
-
-	wstring getStringAttribute(in string name);
-	void setStringAttribute(in string name, in wstring value);
-};
-
--- a/mailnews/addrbook/public/nsIAddrDatabase.idl
+++ b/mailnews/addrbook/public/nsIAddrDatabase.idl
@@ -52,74 +52,17 @@ interface nsIArray;
 // to the mozilla addressbook, and weren't in 4.x and aren't specified in
 // RFC 2789.  used when exporting and import LDIF
 // see nsTextAddress.cpp, nsAddressBook.cpp
 #define MOZ_AB_LDIF_PREFIX "mozilla"
 
 // note, GeneratedName is not a real column
 // if you change any of this, make sure to change 
 // Get / Set CardValue in nsAbCardProperty.cpp
-#define kFirstNameColumn          "FirstName"
-#define kLastNameColumn           "LastName"
-#define kPhoneticFirstNameColumn  "PhoneticFirstName"
-#define kPhoneticLastNameColumn   "PhoneticLastName"
 #define kPhoneticNameColumn       "_PhoneticName"
-#define kDisplayNameColumn        "DisplayName"
-#define kNicknameColumn           "NickName"
-#define kPriEmailColumn           "PrimaryEmail"
-#define k2ndEmailColumn           "SecondEmail"
-#define kPreferMailFormatColumn   "PreferMailFormat"
-#define kPopularityIndexColumn    "PopularityIndex"
-#define kAllowRemoteContentColumn "AllowRemoteContent"
-#define kWorkPhoneColumn          "WorkPhone"
-#define kHomePhoneColumn          "HomePhone"
-#define kFaxColumn                "FaxNumber"
-#define kPagerColumn              "PagerNumber"
-#define kCellularColumn           "CellularNumber"
-#define kWorkPhoneTypeColumn      "WorkPhoneType"
-#define kHomePhoneTypeColumn      "HomePhoneType"
-#define kFaxTypeColumn            "FaxNumberType"
-#define kPagerTypeColumn          "PagerNumberType"
-#define kCellularTypeColumn       "CellularNumberType"
-#define kHomeAddressColumn        "HomeAddress"
-#define kHomeAddress2Column       "HomeAddress2"
-#define kHomeCityColumn           "HomeCity"
-#define kHomeStateColumn          "HomeState"
-#define kHomeZipCodeColumn        "HomeZipCode"
-#define kHomeCountryColumn        "HomeCountry"
-#define kWorkAddressColumn        "WorkAddress"
-#define kWorkAddress2Column       "WorkAddress2"
-#define kWorkCityColumn           "WorkCity"
-#define kWorkStateColumn          "WorkState"
-#define kWorkZipCodeColumn        "WorkZipCode"
-#define kWorkCountryColumn        "WorkCountry"
-#define kJobTitleColumn           "JobTitle"
-#define kDepartmentColumn         "Department"
-#define kCompanyColumn            "Company"
-#define kAimScreenNameColumn      "_AimScreenName"
-#define kAnniversaryYearColumn    "AnniversaryYear"
-#define kAnniversaryMonthColumn   "AnniversaryMonth"
-#define kAnniversaryDayColumn     "AnniversaryDay"
-#define kSpouseNameColumn         "SpouseName"
-#define kFamilyNameColumn         "FamilyName"
-#define kDefaultAddressColumn     "DefaultAddress"
-#define kCategoryColumn           "Category"
-// webPage1 is work web page
-#define kWebPage1Column           "WebPage1"
-// webPage2 is home web page
-#define kWebPage2Column           "WebPage2"
-#define kBirthYearColumn          "BirthYear"
-#define kBirthMonthColumn         "BirthMonth"
-#define kBirthDayColumn           "BirthDay"
-#define kCustom1Column            "Custom1"
-#define kCustom2Column            "Custom2"
-#define kCustom3Column            "Custom3"
-#define kCustom4Column            "Custom4"
-#define kNotesColumn              "Notes"
-#define kLastModifiedDateColumn   "LastModifiedDate"
 #define kAddressCharSetColumn     "AddrCharSet"
 #define kMailListName             "ListName"
 #define kMailListNickName         "ListNickName"
 #define kMailListDescription      "ListDescription"
 #define kMailListTotalAddresses   "ListTotalAddresses"
 // not shown in the UI
 #define kLowerPriEmailColumn      "LowercasePrimaryEmail"
 
--- a/mailnews/addrbook/resources/content/abCardOverlay.js
+++ b/mailnews/addrbook/resources/content/abCardOverlay.js
@@ -42,56 +42,56 @@ const kNonVcardFields =
 
 const kPhoneticFields =
         ["PhoneticLastName", "PhoneticLabel1", "PhoneticSpacer1",
          "PhoneticFirstName", "PhoneticLabel2", "PhoneticSpacer2"];
 
 // Item is |[dialogField, cardProperty]|.
 const kVcardFields =
         [ // Contact > Name
-         ["FirstName", "firstName"],
-         ["LastName", "lastName"],
-         ["DisplayName", "displayName"],
-         ["NickName", "nickName"],
+         ["FirstName", "FirstName"],
+         ["LastName", "LastName"],
+         ["DisplayName", "DisplayName"],
+         ["NickName", "NickName"],
           // Contact > Internet
-         ["PrimaryEmail", "primaryEmail"],
-         ["SecondEmail", "secondEmail"],
-         ["ScreenName", "aimScreenName"], // NB: AIM.
+         ["PrimaryEmail", "PrimaryEmail"],
+         ["SecondEmail", "SecondEmail"],
+         ["ScreenName", "_AimScreenName"], // NB: AIM.
           // Contact > Phones
-         ["WorkPhone", "workPhone"],
-         ["HomePhone", "homePhone"],
-         ["FaxNumber", "faxNumber"],
-         ["PagerNumber", "pagerNumber"],
-         ["CellularNumber", "cellularNumber"],
+         ["WorkPhone", "WorkPhone"],
+         ["HomePhone", "HomePhone"],
+         ["FaxNumber", "FaxNumber"],
+         ["PagerNumber", "PagerNumber"],
+         ["CellularNumber", "CellularNumber"],
           // Address > Home
-         ["HomeAddress", "homeAddress"],
-         ["HomeAddress2", "homeAddress2"],
-         ["HomeCity", "homeCity"],
-         ["HomeState", "homeState"],
-         ["HomeZipCode", "homeZipCode"],
-         ["HomeCountry", "homeCountry"],
-         ["WebPage2", "webPage2"],
+         ["HomeAddress", "HomeAddress"],
+         ["HomeAddress2", "HomeAddress2"],
+         ["HomeCity", "HomeCity"],
+         ["HomeState", "HomeState"],
+         ["HomeZipCode", "HomeZipCode"],
+         ["HomeCountry", "HomeCountry"],
+         ["WebPage2", "WebPage2"],
           // Address > Work
-         ["JobTitle", "jobTitle"],
-         ["Department", "department"],
-         ["Company", "company"],
-         ["WorkAddress", "workAddress"],
-         ["WorkAddress2", "workAddress2"],
-         ["WorkCity", "workCity"],
-         ["WorkState", "workState"],
-         ["WorkZipCode", "workZipCode"],
-         ["WorkCountry", "workCountry"],
-         ["WebPage1", "webPage1"],
+         ["JobTitle", "JobTitle"],
+         ["Department", "Department"],
+         ["Company", "Company"],
+         ["WorkAddress", "WorkAddress"],
+         ["WorkAddress2", "WorkAddress2"],
+         ["WorkCity", "WorkCity"],
+         ["WorkState", "WorkState"],
+         ["WorkZipCode", "WorkZipCode"],
+         ["WorkCountry", "WorkCountry"],
+         ["WebPage1", "WebPage1"],
           // Other > (custom)
-         ["Custom1", "custom1"],
-         ["Custom2", "custom2"],
-         ["Custom3", "custom3"],
-         ["Custom4", "custom4"],
+         ["Custom1", "Custom1"],
+         ["Custom2", "Custom2"],
+         ["Custom3", "Custom3"],
+         ["Custom4", "Custom4"],
           // Other > Notes
-         ["Notes", "notes"]];
+         ["Notes", "Notes"]];
 
 var gEditCard;
 var gOnSaveListeners = new Array();
 var gOkCallback = null;
 var gHideABPicker = false;
 
 function OnLoadNewCard()
 {
@@ -132,22 +132,22 @@ function OnLoadNewCard()
       gEditCard.card.displayName = window.arguments[0].displayName;
       // if we've got a display name, don't generate
       // a display name (and stomp on the existing display name)
       // when the user types a first or last name
       if (gEditCard.card.displayName.length)
         gEditCard.generateDisplayName = false;
     }
     if ("aimScreenName" in window.arguments[0])
-      gEditCard.card.aimScreenName = window.arguments[0].aimScreenName;
+      gEditCard.card.setProperty("_AimScreenName",
+                                 window.arguments[0].aimScreenName);
     
-    if ("allowRemoteContent" in window.arguments[0]) {
-      gEditCard.card.allowRemoteContent = window.arguments[0].allowRemoteContent;
-      window.arguments[0].allowRemoteContent = false;
-    }
+    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 =
@@ -363,17 +363,17 @@ function InitEditCard()
 
 function NewCardOKButton()
 {
   if (gOkCallback)
   {
     if (!CheckAndSetCardValues(gEditCard.card, document, true))
       return false;  // don't close window
 
-    gOkCallback(gEditCard.card.convertToEscapedVCard());
+    gOkCallback(gEditCard.card.translateTo("vcard"));
     return true;  // close the window
   }
 
   var popup = document.getElementById('abPopup');
   if ( popup )
   {
     var uri = popup.getAttribute('value');
 
@@ -389,45 +389,47 @@ 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.
       gEditCard.card = GetDirectoryFromURI(uri).addCard(gEditCard.card);
       NotifySaveListeners();
       if ("arguments" in window && window.arguments[0])
-        window.arguments[0].allowRemoteContent = gEditCard.card.allowRemoteContent;
+        window.arguments[0].allowRemoteContent =
+          gEditCard.card.getProperty("AllowRemoteContent", false));
     }
   }
 
   return true;  // close the window
 }
 
 // Move the data from the cardproperty to the dialog
 function GetCardValues(cardproperty, doc)
 {
   if (!cardproperty)
     return;
 
-  for (var i = kVcardFields.length; i-- > 0; )
+  for (var i = kVcardFields.length; i-- > 0; ) {
     doc.getElementById(kVcardFields[i][0]).value =
-      cardproperty[kVcardFields[i][1]];
+      cardproperty.getProperty(kVcardFields[i][1], "");
+  }
 
   var popup = document.getElementById("PreferMailFormatPopup");
   if (popup)
-    popup.value = cardproperty.preferMailFormat;
+    popup.value = cardproperty.getProperty("PreferMailFormat", "");
     
   var allowRemoteContentEl = document.getElementById("allowRemoteContent");
   if (allowRemoteContentEl)
-    allowRemoteContentEl.checked = cardproperty.allowRemoteContent;
+    allowRemoteContentEl.checked = cardproperty.getProperty("AllowRemoteContent", false);
 
   // get phonetic fields if exist
   try {
-    doc.getElementById("PhoneticFirstName").value = cardproperty.phoneticFirstName;
-    doc.getElementById("PhoneticLastName").value = cardproperty.phoneticLastName;
+    doc.getElementById("PhoneticFirstName").value = cardproperty.getProperty("PhoneticFirstName", "");
+    doc.getElementById("PhoneticLastName").value = cardproperty.getProperty("PhoneticLastName", "");
   }
   catch (ex) {}
 }
 
 // when the ab card dialog is being loaded to show a vCard,
 // hide the fields which aren't supported
 // by vCard so the user does not try to edit them.
 function HideNonVcardFields()
@@ -444,31 +446,31 @@ function CheckAndSetCardValues(cardprope
   // If requested, check the required data presence.
   if (check && !CheckCardRequiredDataPresence(document))
     return false;
 
   if (!cardproperty)
     return true;
 
   for (var i = kVcardFields.length; i-- > 0; )
-    cardproperty[kVcardFields[i][1]] =
-      doc.getElementById(kVcardFields[i][0]).value;
+    cardproperty.setProperty(kVcardFields[i][1],
+      doc.getElementById(kVcardFields[i][0]).value);
 
   var popup = document.getElementById("PreferMailFormatPopup");
   if (popup)
-    cardproperty.preferMailFormat = popup.value;
+    cardproperty.setProperty("PreferMailFormat", popup.value);
     
   var allowRemoteContentEl = document.getElementById("allowRemoteContent");
   if (allowRemoteContentEl)
-    cardproperty.allowRemoteContent = allowRemoteContentEl.checked;    
+    cardproperty.setProperty("AllowRemoteContent", allowRemoteContentEl.checked);
 
   // set phonetic fields if exist
   try {
-    cardproperty.phoneticFirstName = doc.getElementById("PhoneticFirstName").value;
-    cardproperty.phoneticLastName = doc.getElementById("PhoneticLastName").value;
+    cardproperty.setProperty("PhoneticFirstName", doc.getElementById("PhoneticFirstName").value);
+    cardproperty.setProperty("PhoneticLastName", doc.getElementById("PhoneticLastName").value);
   }
   catch (ex) {}
 
   return true;
 }
 
 function CleanUpWebPage(webPage)
 {
--- a/mailnews/addrbook/resources/content/abCardViewOverlay.js
+++ b/mailnews/addrbook/resources/content/abCardViewOverlay.js
@@ -185,37 +185,45 @@ function GetAddressesFromURI(uri)
   return addresses;
 }
 
 function GoIM()
 {
   LaunchUrl(top.cvData.cvAimPresence.getAttribute("url"));
 }
 
-function DisplayCardViewPane(card)
+function DisplayCardViewPane(realCard)
 {
-  var generatedName = card.generateName(gPrefs.getIntPref("mail.addr_book.lastnamefirst"));
+  var generatedName = realCard.generateName(gPrefs.getIntPref("mail.addr_book.lastnamefirst"));
 		
   var data = top.cvData;
   var visible;
 
+  var card = { getProperty : function (prop) {
+                 return realCard.getProperty(prop, "");
+               },
+               primaryEmail : realCard.primaryEmail,
+               displayName : realCard.displayName,
+               isMailList : realCard.isMailList,
+               mailListURI : realCard.mailListURI
+  };
   var titleString;
   if (generatedName == "")
     titleString = card.primaryEmail;  // if no generatedName, use email
   else
     titleString = generatedName;
 
   // set fields in card view pane
   if (card.isMailList)
     cvSetNode(data.CardTitle, gAddressBookBundle.getFormattedString("viewListTitle", [generatedName]));
   else
     cvSetNode(data.CardTitle, gAddressBookBundle.getFormattedString("viewCardTitle", [titleString]));
 	
   // Contact section
-  cvSetNodeWithLabel(data.cvNickname, zNickname, card.nickName);
+  cvSetNodeWithLabel(data.cvNickname, zNickname, card.getProperty("NickName"));
 
   if (card.isMailList) {
     // email1, display name and screenname always hidden when a mailing list.
     cvSetVisible(data.cvDisplayName, false);
     cvSetVisible(data.cvEmail1Box, false);
     cvSetVisible(data.cvScreennameBox, false);
 
     visible = HandleLink(data.cvListName, zListName, card.displayName, data.cvListNameBox, "mailto:" + encodeURIComponent(GenerateAddressFromCard(card))) || visible;
@@ -225,121 +233,121 @@ function DisplayCardViewPane(card)
     cvSetVisible(data.cvListNameBox, false);
 
     cvSetNodeWithLabel(data.cvDisplayName, zDisplayName, card.displayName);
 
     visible = HandleLink(data.cvEmail1, zPrimaryEmail, card.primaryEmail, data.cvEmail1Box, "mailto:" + card.primaryEmail) || visible;
   }
 
   var onlineCheckAllowed = gPrefs.getBoolPref("mail.addr_book.im.onlineCheckAllowed");
-  var goimURL = "aim:goim?screenname=" + card.aimScreenName;
-  var hasScreenName = HandleLink(data.cvScreenname, zScreenName, card.aimScreenName, data.cvScreennameBox, goimURL);
+  var goimURL = "aim:goim?screenname=" + card.getProperty("_AimScreenName");
+  var hasScreenName = HandleLink(data.cvScreenname, zScreenName, card.getProperty("_AimScreenName"), data.cvScreennameBox, goimURL);
 
   if (!onlineCheckAllowed || !hasScreenName || gIOService.offline) {
     data.cvAimPresence.removeAttribute("src");
     data.cvAimPresence.removeAttribute("url");
     data.cvAimPresence.setAttribute("width","0");
   }
   else {
-    data.cvAimPresence.setAttribute("src","http://big.oscar.aol.com:80/" + card.aimScreenName + "?on_url=http://ncmail.netscape.com/include/nc/images/online.gif&off_url=http://ncmail.netscape.com/include/nc/images/offline.gif");   
+    data.cvAimPresence.setAttribute("src","http://big.oscar.aol.com:80/" + card.getProperty("_AimScreenName") + "?on_url=http://ncmail.netscape.com/include/nc/images/online.gif&off_url=http://ncmail.netscape.com/include/nc/images/offline.gif");   
     data.cvAimPresence.setAttribute("url", goimURL);
     data.cvAimPresence.setAttribute("width","16");
   }
 
   visible = hasScreenName || visible;
-  visible = HandleLink(data.cvEmail2, zSecondaryEmail, card.secondEmail, data.cvEmail2Box, "mailto:" + card.secondEmail) || visible;
+  visible = HandleLink(data.cvEmail2, zSecondaryEmail, card.getProperty("SecondEmail"), data.cvEmail2Box, "mailto:" + card.getProperty("SecondEmail")) || visible;
 
 	// Home section
-	visible = cvSetNode(data.cvHomeAddress, card.homeAddress);
-	visible = cvSetNode(data.cvHomeAddress2, card.homeAddress2) || visible;
-	visible = cvSetCityStateZip(data.cvHomeCityStZip, card.homeCity, card.homeState, card.homeZipCode) || visible;
-	visible = cvSetNode(data.cvHomeCountry, card.homeCountry) || visible;
+	visible = cvSetNode(data.cvHomeAddress, card.getProperty("HomeAddress"));
+	visible = cvSetNode(data.cvHomeAddress2, card.getProperty("HomeAddress2")) || visible;
+	visible = cvSetCityStateZip(data.cvHomeCityStZip, card.getProperty("HomeCity"), card.getProperty("HomeState"), card.getProperty("HomeZipCode")) || visible;
+	visible = cvSetNode(data.cvHomeCountry, card.getProperty("HomeCountry")) || visible;
         if (visible) {
-          var homeMapItUrl = CreateMapItURL(card.homeAddress, card.homeAddress2, card.homeCity, card.homeState, card.homeZipCode, card.homeCountry);
+          var homeMapItUrl = CreateMapItURL(card.getProperty("HomeAddress"), card.getProperty("HomeAddress2"), card.getProperty("HomeCity"), card.getProperty("HomeState"), card.getProperty("HomeZipCode"), card.getProperty("HomeCountry"));
           if (homeMapItUrl) {
 	    cvSetVisible(data.cvbHomeMapItBox, true);
             data.cvHomeMapIt.setAttribute('url', homeMapItUrl);
           }
           else {
 	    cvSetVisible(data.cvbHomeMapItBox, false);
           }
         }
         else {
 	  cvSetVisible(data.cvbHomeMapItBox, false);
         }
 
-  visible = HandleLink(data.cvHomeWebPage, "", card.webPage2, data.cvHomeWebPageBox, card.webPage2) || visible;
+  visible = HandleLink(data.cvHomeWebPage, "", card.getProperty("WebPage2"), data.cvHomeWebPageBox, card.getProperty("WebPage2")) || visible;
 
 	cvSetVisible(data.cvhHome, visible);
 	cvSetVisible(data.cvbHome, visible);
   if (card.isMailList) {
     // Description section
-	  visible = cvSetNode(data.cvDescription, card.notes)
+	  visible = cvSetNode(data.cvDescription, card.getProperty("Notes"))
   	cvSetVisible(data.cvbDescription, visible);
 
     // Addresses section
 	  visible = cvAddAddressNodes(data.cvAddresses, card.mailListURI);
   	cvSetVisible(data.cvbAddresses, visible);
  
     // Other section, not shown for mailing lists.
     cvSetVisible(data.cvbOther, false);
   }
   else {
 	  // Other section
-	  visible = cvSetNodeWithLabel(data.cvCustom1, zCustom1, card.custom1);
-	  visible = cvSetNodeWithLabel(data.cvCustom2, zCustom2, card.custom2) || visible;
-	  visible = cvSetNodeWithLabel(data.cvCustom3, zCustom3, card.custom3) || visible;
-	  visible = cvSetNodeWithLabel(data.cvCustom4, zCustom4, card.custom4) || visible;
-	  visible = cvSetNode(data.cvNotes, card.notes) || visible;
+	  visible = cvSetNodeWithLabel(data.cvCustom1, zCustom1, card.getProperty("Custom1"));
+	  visible = cvSetNodeWithLabel(data.cvCustom2, zCustom2, card.getProperty("Custom2")) || visible;
+	  visible = cvSetNodeWithLabel(data.cvCustom3, zCustom3, card.getProperty("Custom3")) || visible;
+	  visible = cvSetNodeWithLabel(data.cvCustom4, zCustom4, card.getProperty("Custom4")) || visible;
+	  visible = cvSetNode(data.cvNotes, card.getProperty("Notes")) || visible;
     visible = setBuddyIcon(card, data.cvBuddyIcon) || visible;
 
     cvSetVisible(data.cvhOther, visible);
     cvSetVisible(data.cvbOther, visible);
 
     // hide description section, not show for non-mailing lists
     cvSetVisible(data.cvbDescription, false);
 
     // hide addresses section, not show for non-mailing lists
     cvSetVisible(data.cvbAddresses, false);
   }
 
 	// Phone section
-	visible = cvSetNodeWithLabel(data.cvPhWork, zWork, card.workPhone);
-	visible = cvSetNodeWithLabel(data.cvPhHome, zHome, card.homePhone) || visible;
-	visible = cvSetNodeWithLabel(data.cvPhFax, zFax, card.faxNumber) || visible;
-	visible = cvSetNodeWithLabel(data.cvPhCellular, zCellular, card.cellularNumber) || visible;
-	visible = cvSetNodeWithLabel(data.cvPhPager, zPager, card.pagerNumber) || visible;
+	visible = cvSetNodeWithLabel(data.cvPhWork, zWork, card.getProperty("WorkPhone"));
+	visible = cvSetNodeWithLabel(data.cvPhHome, zHome, card.getProperty("HomePhone")) || visible;
+	visible = cvSetNodeWithLabel(data.cvPhFax, zFax, card.getProperty("FaxNumber")) || visible;
+	visible = cvSetNodeWithLabel(data.cvPhCellular, zCellular, card.getProperty("CellularNumber")) || visible;
+	visible = cvSetNodeWithLabel(data.cvPhPager, zPager, card.getProperty("PagerNumber")) || visible;
 	cvSetVisible(data.cvhPhone, visible);
 	cvSetVisible(data.cvbPhone, visible);
 	// Work section
-	visible = cvSetNode(data.cvJobTitle, card.jobTitle);
-	visible = cvSetNode(data.cvDepartment, card.department) || visible;
-	visible = cvSetNode(data.cvCompany, card.company) || visible;
+	visible = cvSetNode(data.cvJobTitle, card.getProperty("JobTitle"));
+	visible = cvSetNode(data.cvDepartment, card.getProperty("Department")) || visible;
+	visible = cvSetNode(data.cvCompany, card.getProperty("Company")) || visible;
         
-        var addressVisible = cvSetNode(data.cvWorkAddress, card.workAddress);
-	addressVisible = cvSetNode(data.cvWorkAddress2, card.workAddress2) || addressVisible;
-	addressVisible = cvSetCityStateZip(data.cvWorkCityStZip, card.workCity, card.workState, card.workZipCode) || addressVisible;
-	addressVisible = cvSetNode(data.cvWorkCountry, card.workCountry) || addressVisible;
+        var addressVisible = cvSetNode(data.cvWorkAddress, card.getProperty("WorkAddress"));
+	addressVisible = cvSetNode(data.cvWorkAddress2, card.getProperty("WorkAddress2")) || addressVisible;
+	addressVisible = cvSetCityStateZip(data.cvWorkCityStZip, card.getProperty("WorkCity"), card.getProperty("WorkState"), card.getProperty("WorkZipCode")) || addressVisible;
+	addressVisible = cvSetNode(data.cvWorkCountry, card.getProperty("WorkCountry")) || addressVisible;
 
         if (addressVisible) {
-          var workMapItUrl = CreateMapItURL(card.workAddress, card.workAddress2, card.workCity, card.workState, card.workZipCode, card.workCountry);
+          var workMapItUrl = CreateMapItURL(card.getProperty("WorkAddress"), card.getProperty("WorkAddress2"), card.getProperty("WorkCity"), card.getProperty("WorkState"), card.getProperty("WorkZipCode"), card.getProperty("WorkCountry"));
           data.cvWorkMapIt.setAttribute('url', workMapItUrl);
           if (workMapItUrl) {
 	    cvSetVisible(data.cvbWorkMapItBox, true);
             data.cvWorkMapIt.setAttribute('url', workMapItUrl);
           }
           else {
 	    cvSetVisible(data.cvbWorkMapItBox, false);
           }
         }
         else {
 	  cvSetVisible(data.cvbWorkMapItBox, false);
         }
 
-        visible = HandleLink(data.cvWorkWebPage, "", card.webPage1, data.cvWorkWebPageBox, card.webPage1) || addressVisible || visible;
+        visible = HandleLink(data.cvWorkWebPage, "", card.getProperty("WebPage1"), data.cvWorkWebPageBox, card.getProperty("WebPage1")) || addressVisible || visible;
 
 	cvSetVisible(data.cvhWork, visible);
 	cvSetVisible(data.cvbWork, visible);
 
 	// make the card view box visible
 	cvSetVisible(top.cvData.CardViewBox, true);
 }
 
@@ -352,17 +360,17 @@ function setBuddyIcon(card, buddyIcon)
         // lazily create these file urls, and keep them around
         var dirService = Components.classes["@mozilla.org/file/directory_service;1"]
             .getService(Components.interfaces.nsIProperties);
         var profileDir = dirService.get("ProfD", Components.interfaces.nsIFile);
         gProfileDirURL = gIOService.newFileURI(profileDir);
       }
 
       // if we did have a buddy icon on disk for this screenname, this would be the file url spec for it
-      var iconURLStr = gProfileDirURL.spec + "/NIM/" + myScreenName + "/picture/" + card.aimScreenName + ".gif";
+      var iconURLStr = gProfileDirURL.spec + "/NIM/" + myScreenName + "/picture/" + card.getProperty("_AimScreenName") + ".gif";
 
       // check if the file exists
       var file = gFileHandler.getFileFromURLSpec(iconURLStr);
             
       // check if the file exists
       // is this a perf hit?  (how expensive is stat()?)
       if (file.exists()) {
         buddyIcon.setAttribute("src", iconURLStr);
--- a/mailnews/addrbook/resources/content/abMailListDialog.js
+++ b/mailnews/addrbook/resources/content/abMailListDialog.js
@@ -255,18 +255,18 @@ function EditListOKButton()
 {
   //edit mailing list in database
   if (GetListValue(gEditList, false))
   {
     if (gListCard) {
       // modify the list card (for the results pane) from the mailing list 
       gListCard.displayName = gEditList.dirName;
       gListCard.lastName = gEditList.dirName;
-      gListCard.nickName = gEditList.listNickName;
-      gListCard.notes = gEditList.description;
+      gListCard.setProperty("NickName", gEditList.listNickName);
+      gListCard.setProperty("Notes", gEditList.description);
     }
 
     gEditList.editMailListToDatabase(gListCard);
 
     if (gOkCallback)
       gOkCallback();
     return true;  // close the window
   }
--- a/mailnews/addrbook/resources/content/addressbook.js
+++ b/mailnews/addrbook/resources/content/addressbook.js
@@ -337,18 +337,17 @@ function AbPrintCard()
 
 function AbPrintPreviewCard()
 {
   AbPrintCardInternal(true, Components.interfaces.nsIMsgPrintEngine.MNAB_PRINTPREVIEW_AB_CARD);
 }
 
 function CreatePrintCardUrl(card)
 {
-  var url = "data:application/xml;base64," + card.convertToBase64EncodedXML();
-  return url;
+  return "data:application/xml;base64," + card.translateTo("base64xml");
 }
 
 function AbPrintAddressBookInternal(doPrintPreview, msgType)
 {
   var uri = GetSelectedDirectory();
   if (!uri)
     return;
 
@@ -630,17 +629,17 @@ function AbIMSelected()
 {
   var cards = GetSelectedAbCards();
   var count = cards.length;
 
   var screennames;
   var screennameCount = 0;
 
   for (var i=0;i<count;i++) {
-    var screenname = cards[i].aimScreenName;
+    var screenname = cards[i].getProperty("_AimScreenName", "");
     if (screenname) {
       if (screennameCount == 0)
         screennames = screenname;
       else
         screennames += "," + screenname;
 
       screennameCount++
     }
--- a/mailnews/addrbook/src/nsAbAddressCollecter.cpp
+++ b/mailnews/addrbook/src/nsAbAddressCollecter.cpp
@@ -125,41 +125,40 @@ NS_IMETHODIMP nsAbAddressCollecter::Coll
     if (curAddress.IsEmpty())
       continue;
 
 
     nsCOMPtr <nsIAbCard> existingCard;
     nsCOMPtr <nsIAbCard> cardInstance;
     PRBool emailAddressIn2ndEmailColumn = PR_FALSE;
 
-    rv = GetCardFromAttribute(NS_LITERAL_CSTRING(kPriEmailColumn), curAddress,
+    rv = GetCardFromAttribute(NS_LITERAL_CSTRING(kPriEmailProperty), curAddress,
                               getter_AddRefs(existingCard));
     // We've not found a card, but is this address actually in the additional
     // email column?
     if (!existingCard)
     {
-      rv = GetCardFromAttribute(NS_LITERAL_CSTRING(k2ndEmailColumn), curAddress,
+      rv = GetCardFromAttribute(NS_LITERAL_CSTRING(k2ndEmailProperty), curAddress,
                                 getter_AddRefs(existingCard));
       if (existingCard)
         emailAddressIn2ndEmailColumn = PR_TRUE;
     }
 
     if (!existingCard && aCreateCard)
     {
       nsCOMPtr<nsIAbCard> senderCard = do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID, &rv);
       if (NS_SUCCEEDED(rv) && senderCard && m_directory)
       {
         // Set up the fields for the new card.
         SetNamesForCard(senderCard, unquotedName);
         AutoCollectScreenName(senderCard, curAddress);
 
         if (NS_SUCCEEDED(senderCard->SetPrimaryEmail(NS_ConvertUTF8toUTF16(curAddress))))
         {
-          if (aSendFormat != nsIAbPreferMailFormat::unknown)
-            senderCard->SetPreferMailFormat(aSendFormat);
+          senderCard->SetPropertyAsUint32(kPreferMailFormatProperty, aSendFormat);
 
           nsCOMPtr<nsIAbCard> addedCard;
           rv = m_directory->AddCard(senderCard, getter_AddRefs(addedCard));
           NS_ASSERTION(NS_SUCCEEDED(rv), "failed to add card");
         }
       }
     }
     else if (existingCard && !emailAddressIn2ndEmailColumn) { 
@@ -170,22 +169,22 @@ NS_IMETHODIMP nsAbAddressCollecter::Coll
       existingCard->GetDisplayName(displayName);
       // If we already have a display name, don't set the names on the card.
       if (displayName.IsEmpty() && !unquotedName.IsEmpty())
         modifiedCard = SetNamesForCard(existingCard, unquotedName);
 
       if (aSendFormat != nsIAbPreferMailFormat::unknown)
       {
         PRUint32 currentFormat;
-        rv = existingCard->GetPreferMailFormat(&currentFormat);
+        rv = existingCard->GetPropertyAsUint32(kPreferMailFormatProperty, &currentFormat);
         NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get preferred mail format");
 
         // we only want to update the AB if the current format is unknown
         if (currentFormat == nsIAbPreferMailFormat::unknown &&
-            NS_SUCCEEDED(existingCard->SetPreferMailFormat(aSendFormat)))
+            NS_SUCCEEDED(existingCard->SetPropertyAsUint32(kPreferMailFormatProperty, aSendFormat)))
           modifiedCard = PR_TRUE;
       }
 
       if (modifiedCard && m_directory)
         m_directory->ModifyCard(existingCard);
     }
   } 
 
@@ -211,17 +210,17 @@ nsAbAddressCollecter::AutoCollectScreenN
   // username in 
   // username@aol.com (America Online)
   // username@cs.com (Compuserve)
   // username@netscape.net (Netscape webmail)
   // are all AIM screennames.  autocollect that info.
   if (!domain.IsEmpty() &&
       (domain.Equals("aol.com") || domain.Equals("cs.com") ||
        domain.Equals("netscape.net")))
-    aCard->SetAimScreenName(NS_ConvertUTF8toUTF16(Substring(aEmail, 0, atPos)));
+    aCard->SetPropertyAsAUTF8String(kScreenNameProperty, Substring(aEmail, 0, atPos));
 }
 
 // Returns true if the card was modified successfully.
 PRBool
 nsAbAddressCollecter::SetNamesForCard(nsIAbCard *aSenderCard,
                                       const nsCString &aFullName)
 {
   nsCString firstName;
--- a/mailnews/addrbook/src/nsAbAutoCompleteSearch.js
+++ b/mailnews/addrbook/src/nsAbAutoCompleteSearch.js
@@ -128,47 +128,51 @@ nsAbAutoCompleteSearch.prototype = {
 
   // fullString is the full search string.
   // firstWord is the first word of the search string.
   // rest is anything after the first word.
   _checkEntry: function _checkEntry(card, fullString, firstWord, rest) {
     var i;
     if (card.isMailList) {
       return card.displayName.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
-        card.notes.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
-        card.nickName.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0;
+        card.getProperty("Notes", "").toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
+        card.getProperty("NickName", "").toLocaleLowerCase().lastIndexOf(fullString, 0) == 0;
     }
 
-    if (card.nickName.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
-        card.displayName.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
-        card.firstName.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
-        card.lastName.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
+    var firstName = card.firstName.toLocaleLowerCase();
+    var lastName = card.lastName.toLocaleLowerCase();
+    if (card.displayName.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0 ||
+        firstName.lastIndexOf(fullString, 0) == 0 ||
+        lastName.lastIndexOf(fullString, 0) == 0 ||
         card.primaryEmail.toLocaleLowerCase().lastIndexOf(fullString, 0) == 0)
       return true;
 
     if (firstWord && rest &&
-        ((card.firstName.toLocaleLowerCase().lastIndexOf(firstWord, 0) == 0 &&
-          card.lastName.toLocaleLowerCase().lastIndexOf(rest, 0) == 0) ||
-         (card.firstName.toLocaleLowerCase().lastIndexOf(rest, 0) == 0 &&
-          card.lastName.toLocaleLowerCase().lastIndexOf(firstWord, 0) == 0)))
+        ((firstName.lastIndexOf(firstWord, 0) == 0 &&
+          lastName.lastIndexOf(rest, 0) == 0) ||
+         (firstName.lastIndexOf(rest, 0) == 0 &&
+          lastName.lastIndexOf(firstWord, 0) == 0)))
+      return true;
+
+    if (card.getProperty("NickName", "").toLocaleLowerCase().lastIndexOf(fullString, 0) == 0)
       return true;
 
     return false;
   },
 
   _checkDuplicate: function _checkDuplicate(card, emailAddress, currentResults) {
     var lcEmailAddress = emailAddress.toLocaleLowerCase();
 
+    var popIndex = parseInt(card.getProperty("PopularityIndex", "0"));
     for (var i = 0; i < currentResults._searchResults.length; ++i) {
       if (currentResults._searchResults[i].value.toLocaleLowerCase() ==
           lcEmailAddress)
       {
         // It's a duplicate, is the new one is more popular?
-        if (card.popularityIndex >
-            currentResults._searchResults[i].card.popularityIndex) {
+        if (popIndex > currentResults._searchResults[i].popularity) {
           // Yes it is, so delete this element, return false and allow
           // _addToResult to sort the new element into the correct place.
           currentResults._searchResults.splice(i, 1);
           return false;
         }
         // Not more popular, but still a duplicate. Return true and _addToResult
         // will just forget about it.
         return true;
@@ -176,50 +180,52 @@ nsAbAutoCompleteSearch.prototype = {
     }
     return false;
   },
 
   _addToResult: function _addToResult(commentColumn, card, result) {
     var emailAddress =
       this._parser.makeFullAddress(card.displayName,
                                    card.isMailList ?
-                                   card.notes || card.displayName :
+                                   card.getProperty("Notes", "") || card.displayName :
                                    card.primaryEmail);
 
     // The old code used to try it manually. I think if the parser can't work
     // out the address from what we've supplied, then its busted and we're not
     // going to do any better doing it manually.
     if (!emailAddress)
       return;
 
     // If it is a duplicate, then just return and don't add it. The
     // _checkDuplicate function deals with it all for us.
     if (this._checkDuplicate(card, emailAddress, result))
       return;
 
     // Find out where to insert the card.
     var insertPosition = 0;
-    var cardPopularityIndex = card.popularityIndex;
+    // Hack - mork adds in as a string, but we want to get as an integer...
+    var cardPopularityIndex = parseInt(card.getProperty("PopularityIndex", "0"));
 
     while (insertPosition < result._searchResults.length &&
            cardPopularityIndex <
-           result._searchResults[insertPosition].card.popularityIndex)
+           result._searchResults[insertPosition].popularity)
       ++insertPosition;
 
     // Next sort on full address
     while (insertPosition < result._searchResults.length &&
            cardPopularityIndex ==
-           result._searchResults[insertPosition].card.popularityIndex &&
+           result._searchResults[insertPosition].popularity &&
            emailAddress > result._searchResults[insertPosition].value)
       ++insertPosition;
 
     result._searchResults.splice(insertPosition, 0, {
       value: emailAddress,
       comment: commentColumn,
-      card: card
+      card: card,
+      popularity: cardPopularityIndex
     });
   },
 
   // nsIAutoCompleteSearch
   startSearch: function startSearch(aSearchString, aSearchParam,
                                     aPreviousResult, aListener) {
     var result = new nsAbAutoCompleteResult(aSearchString);
 
@@ -264,17 +270,18 @@ nsAbAutoCompleteSearch.prototype = {
         if (this._checkEntry(aPreviousResult.getCardAt(i), fullString,
                              firstWord, rest))
           // If it matches, just add it straight onto the array, these will
           // already be in order because the previous search returned them
           // in the correct order.
           result._searchResults.push({
             value: aPreviousResult.getValueAt(i),
             comment: aPreviousResult.getCommentAt(i),
-            card: aPreviousResult.getCardAt(i)
+            card: aPreviousResult.getCardAt(i),
+            popularity: parseInt(aPreviousResult.getCardAt(i).getProperty("PopularityIndex", "0"))
           });
       }
     }
     else
     {
       // Now do the searching
       var allABs = Components.classes["@mozilla.org/abmanager;1"]
                              .getService(Components.interfaces.nsIAbManager)
--- a/mailnews/addrbook/src/nsAbAutoCompleteSession.cpp
+++ b/mailnews/addrbook/src/nsAbAutoCompleteSession.cpp
@@ -364,31 +364,31 @@ nsresult nsAbAutoCompleteSession::Search
           PRUint32 popularityIndex = 0;
           PRBool bIsMailList;
 
           rv = card->GetIsMailList(&bIsMailList);
           if (NS_FAILED(rv))
             continue;
           if (bIsMailList)
           {
-            rv = card->GetNotes(pNotesStr);
+            rv = card->GetPropertyAsAString(kNotesProperty, pNotesStr);
             if (NS_FAILED(rv))
               continue;
           }
           else
           {
             for (i = 0 ; i < MAX_NUMBER_OF_EMAIL_ADDRESSES; i ++)
             {
               switch (i)
               {
                 case 0:
                   rv = card->GetPrimaryEmail(pEmailStr[i]);
                   break;
                 case 1:
-                  rv = card->GetSecondEmail(pEmailStr[i]);
+                  rv = card->GetPropertyAsAString(k2ndEmailProperty, pEmailStr[i]);
                   break;
                 default:
                   return NS_ERROR_FAILURE;
               }
               if (NS_FAILED(rv))
                 continue;
 
               // Don't bother with card without an email address
@@ -399,36 +399,32 @@ nsresult nsAbAutoCompleteSession::Search
               if (pEmailStr[i].FindChar('@') <= 0)
                 pEmailStr[i].Truncate();
             }
             if (pEmailStr[0].IsEmpty() && pEmailStr[1].IsEmpty())
               continue;
           }
 
           // Now, retrieve the user name and nickname
-          rv = card->GetDisplayName(pDisplayNameStr);
-          if (NS_FAILED(rv))
-              continue;
-          rv = card->GetFirstName(pFirstNameStr);
-          if (NS_FAILED(rv))
-              continue;
-          rv = card->GetLastName(pLastNameStr);
-          if (NS_FAILED(rv))
-              continue;
-          rv = card->GetNickName(pNickNameStr);
-          if (NS_FAILED(rv))
-              continue;
+          (void)card->GetDisplayName(pDisplayNameStr);
+          (void)card->GetFirstName(pFirstNameStr);
+          (void)card->GetLastName(pLastNameStr);
+
+          (void)card->GetPropertyAsAString(kNicknameProperty, pNickNameStr);
 
-          (void) card->GetPopularityIndex(&popularityIndex);
+          (void)card->GetPropertyAsUint32(kPopularityIndexProperty,
+                                          &popularityIndex);
 
-          // in the address book a mailing list does not have an email address field. However,
-          // we do "fix up" mailing lists in the UI sometimes to look like "My List <My List>"
-          // if we are looking up an address and we are comparing it to a mailing list to see if it is a match
-          // instead of just looking for an exact match on "My List", hijack the unused email address field 
-          // and use that to test against "My List <My List>"
+          // In the address book a mailing list does not have an email address
+          // field. However, we do "fix up" mailing lists in the UI sometimes to
+          // look like "My List <My List>." If we are looking up an address, and
+          // we are comparing it to a mailing list to see if it is a match,
+          // instead of just looking for an exact match on "My List", hijack the
+          // unused email address field and use that to test against
+          // "My List <My List>"
           if (bIsMailList)
             mParser->MakeFullAddress(pDisplayNameStr, pDisplayNameStr, pEmailStr[0]);
 
           for (i = 0 ; i < MAX_NUMBER_OF_EMAIL_ADDRESSES; i ++)
           {
             if (!bIsMailList && pEmailStr[i].IsEmpty())
               continue;
 
--- a/mailnews/addrbook/src/nsAbCardProperty.cpp
+++ b/mailnews/addrbook/src/nsAbCardProperty.cpp
@@ -18,16 +18,17 @@
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Seth Spitzer <sspitzer@netscape.com>
  *   Pierre Phaneuf <pp@ludusdesign.com>
  *   Mark Banner <mark@standard8.demon.co.uk>
+ *   Joshua Cranmer <Pidgeot18@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -53,132 +54,100 @@
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsMemory.h"
 #include "nsVCardObj.h"
 #include "nsIMutableArray.h"
 #include "nsArrayUtils.h"
 #include "mozITXTToHTMLConv.h"
 
+#include "nsIProperty.h"
+#include "nsCOMArray.h"
+#include "nsArrayEnumerator.h"
+
 #define PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST "mail.addr_book.lastnamefirst"
-#define kDisplayName 0
-#define kLastFirst   1
-#define kFirstLast   2
 
 const char sAddrbookProperties[] = "chrome://messenger/locale/addressbook/addressBook.properties";
 
 enum EAppendType {
   eAppendLine,
   eAppendLabel,
   eAppendCityStateZip
 };
 
 struct AppendItem {
   const char *mColumn;
-  const char *mLabel;
+  const char* mLabel;
   EAppendType mAppendType;
 };
 
 static const AppendItem NAME_ATTRS_ARRAY[] = {
-	{kDisplayNameColumn, "propertyDisplayName", eAppendLabel},
-	{kNicknameColumn, "propertyNickname", eAppendLabel},
-	{kPriEmailColumn, "", eAppendLine},
-	{k2ndEmailColumn, "", eAppendLine},
-  {kAimScreenNameColumn, "propertyScreenName", eAppendLabel},
+  {kDisplayNameProperty, "propertyDisplayName", eAppendLabel},
+  {kNicknameProperty, "propertyNickname", eAppendLabel},
+  {kPriEmailProperty, "", eAppendLine},
+  {k2ndEmailProperty, "", eAppendLine},
+  {kScreenNameProperty, "propertyScreenName", eAppendLabel}
 };
 
 static const AppendItem PHONE_ATTRS_ARRAY[] = {
-	{kWorkPhoneColumn, "propertyWork", eAppendLabel},
-	{kHomePhoneColumn, "propertyHome", eAppendLabel},
-	{kFaxColumn, "propertyFax", eAppendLabel},
-	{kPagerColumn, "propertyPager", eAppendLabel},
-	{kCellularColumn, "propertyCellular", eAppendLabel}
+  {kWorkPhoneProperty, "propertyWork", eAppendLabel},
+  {kHomePhoneProperty, "propertyHome", eAppendLabel},
+  {kFaxProperty, "propertyFax", eAppendLabel},
+  {kPagerProperty, "propertyPager", eAppendLabel},
+  {kCellularProperty, "propertyCellular", eAppendLabel}
 };
 
 static const AppendItem HOME_ATTRS_ARRAY[] = {
-	{kHomeAddressColumn, "", eAppendLine},
-	{kHomeAddress2Column, "", eAppendLine},
-	{kHomeCityColumn, "", eAppendCityStateZip},
-	{kHomeCountryColumn, "", eAppendLine},
-	{kWebPage2Column, "", eAppendLine}
+  {kHomeAddressProperty, "", eAppendLine},
+  {kHomeAddress2Property, "", eAppendLine},
+  {kHomeCityProperty, "", eAppendCityStateZip},
+  {kHomeCountryProperty, "", eAppendLine},
+  {kHomeWebPageProperty, "", eAppendLine}
 };
 
 static const AppendItem WORK_ATTRS_ARRAY[] = {
-	{kJobTitleColumn, "", eAppendLine},
-	{kDepartmentColumn, "", eAppendLine},
-	{kCompanyColumn, "", eAppendLine},
-	{kWorkAddressColumn, "", eAppendLine},
-	{kWorkAddress2Column, "", eAppendLine},
-	{kWorkCityColumn, "", eAppendCityStateZip},
-	{kWorkCountryColumn, "", eAppendLine},
-	{kWebPage1Column, "", eAppendLine}
+  {kJobTitleProperty, "", eAppendLine},
+  {kDepartmentProperty, "", eAppendLine},
+  {kCompanyProperty, "", eAppendLine},
+  {kWorkAddressProperty, "", eAppendLine},
+  {kWorkAddress2Property, "", eAppendLine},
+  {kWorkCityProperty, "", eAppendCityStateZip},
+  {kWorkCountryProperty, "", eAppendLine},
+  {kWorkWebPageProperty, "", eAppendLine}
 };
 
 static const AppendItem CUSTOM_ATTRS_ARRAY[] = {
-	{kCustom1Column, "propertyCustom1", eAppendLabel},
-	{kCustom2Column, "propertyCustom2", eAppendLabel},
-	{kCustom3Column, "propertyCustom3", eAppendLabel},
-	{kCustom4Column, "propertyCustom4", eAppendLabel},
-	{kNotesColumn, "", eAppendLine}
+  {kCustom1Property, "propertyCustom1", eAppendLabel},
+  {kCustom2Property, "propertyCustom2", eAppendLabel},
+  {kCustom3Property, "propertyCustom3", eAppendLabel},
+  {kCustom4Property, "propertyCustom4", eAppendLabel},
+  {kNotesProperty, "", eAppendLine}
 };
 
-nsAbCardProperty::nsAbCardProperty(void)
+nsAbCardProperty::nsAbCardProperty()
+  : m_IsMailList(PR_FALSE)
 {
-  m_LastModDate = 0;
+  m_properties.Init();
 
-  m_PreferMailFormat = nsIAbPreferMailFormat::unknown;
-  m_PopularityIndex = 0;
-  m_AllowRemoteContent = PR_FALSE;
-  m_IsMailList = PR_FALSE;
+  // Initialize some default properties
+  SetPropertyAsUint32(kPreferMailFormatProperty, nsIAbPreferMailFormat::unknown);
+  SetPropertyAsUint32(kPopularityIndexProperty, 0);
+  // Uninitialized...
+  SetPropertyAsUint32(kLastModifiedDateProperty, 0);
+  SetPropertyAsBool(kAllowRemoteContentProperty, PR_FALSE);
 }
 
 nsAbCardProperty::~nsAbCardProperty(void)
 {
 }
 
 NS_IMPL_ISUPPORTS1(nsAbCardProperty, nsIAbCard)
 
 ////////////////////////////////////////////////////////////////////////////////
 
-NS_IMETHODIMP nsAbCardProperty::GetPopularityIndex(PRUint32 *aPopularityIndex)
-{
-  *aPopularityIndex = m_PopularityIndex;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbCardProperty::SetPopularityIndex(PRUint32 aPopularityIndex)
-{
-  m_PopularityIndex = aPopularityIndex;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbCardProperty::GetAllowRemoteContent(PRBool *aAllowRemoteContent)
-{
-  *aAllowRemoteContent = m_AllowRemoteContent;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbCardProperty::SetAllowRemoteContent(PRBool aAllowRemoteContent)
-{
-  m_AllowRemoteContent = aAllowRemoteContent;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbCardProperty::GetPreferMailFormat(PRUint32 *aFormat)
-{
-  *aFormat = m_PreferMailFormat;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbCardProperty::SetPreferMailFormat(PRUint32 aFormat)
-{
-  m_PreferMailFormat = aFormat;
-  return NS_OK;
-}
-
 NS_IMETHODIMP nsAbCardProperty::GetIsMailList(PRBool *aIsMailList)
 {
     *aIsMailList = m_IsMailList;
     return NS_OK;
 }
 
 NS_IMETHODIMP nsAbCardProperty::SetIsMailList(PRBool aIsMailList)
 {
@@ -203,744 +172,233 @@ NS_IMETHODIMP nsAbCardProperty::SetMailL
   {
     m_MailListURI = aMailListURI;
     return NS_OK;
   }
   else
     return NS_ERROR_NULL_POINTER;
 }
 
-NS_IMETHODIMP nsAbCardProperty::GetCardValue(const char *attrname, nsAString &value)
+///////////////////////////////////////////////////////////////////////////////
+// Property bag portion of nsAbCardProperty
+///////////////////////////////////////////////////////////////////////////////
+
+class nsAbSimpleProperty : public nsIProperty {
+public:
+    nsAbSimpleProperty(const nsACString& aName, nsIVariant* aValue)
+        : mName(aName), mValue(aValue)
+    {
+    }
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIPROPERTY
+protected:
+    nsCString mName;
+    nsCOMPtr<nsIVariant> mValue;
+};
+
+NS_IMPL_ISUPPORTS1(nsAbSimpleProperty, nsIProperty)
+
+NS_IMETHODIMP
+nsAbSimpleProperty::GetName(nsAString& aName)
+{
+    aName.Assign(NS_ConvertUTF8toUTF16(mName));
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAbSimpleProperty::GetValue(nsIVariant* *aValue)
 {
-  NS_ENSURE_ARG_POINTER(attrname);
+    NS_IF_ADDREF(*aValue = mValue);
+    return NS_OK;
+}
+
+PR_STATIC_CALLBACK(PLDHashOperator)
+PropertyHashToArrayFunc (const nsACString &aKey, nsIVariant* aData, void *userArg)
+{
+  nsCOMArray<nsIProperty>* propertyArray = static_cast<nsCOMArray<nsIProperty> *>(userArg);
+  propertyArray->AppendObject(new nsAbSimpleProperty(aKey, aData));
+  return PL_DHASH_NEXT;
+}
 
-  nsresult rv = NS_OK;
+NS_IMETHODIMP nsAbCardProperty::GetProperties(nsISimpleEnumerator **props)
+{
+  nsCOMArray<nsIProperty> propertyArray(m_properties.Count());
+  m_properties.EnumerateRead(PropertyHashToArrayFunc, &propertyArray);
+  return NS_NewArrayEnumerator(props, propertyArray);
+}
+
+NS_IMETHODIMP nsAbCardProperty::GetProperty(const nsACString &name,
+                                            nsIVariant *defaultValue,
+                                            nsIVariant **value)
+{
+  if (!m_properties.Get(name, value))
+    NS_ADDREF(*value = defaultValue);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsAbCardProperty::GetPropertyAsAString(const char *name, nsAString &value) 
+{
+  nsCOMPtr<nsIVariant> variant;
+  return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ?
+    variant->GetAsAString(value) : NS_ERROR_NOT_AVAILABLE;
+}
 
-  switch (attrname[0]) {
-    case '_': // _AimScreenName
-      rv = GetAimScreenName(value);
-      break;
-    case 'A':
-      // AllowRemoteContent, AnniversaryYear, AnniversaryMonth, AnniversaryDay
-      switch (attrname[11]) {
-        case 'C':
-        {
-          PRBool allowRemoteContent = PR_FALSE;
-          GetAllowRemoteContent(&allowRemoteContent);
-          value = allowRemoteContent ? NS_LITERAL_STRING("true") :
-                                       NS_LITERAL_STRING("false");
-          break;
-        }
-        case 'Y':
-          rv = GetAnniversaryYear(value);
-          break;
-        case 'M':
-          rv = GetAnniversaryMonth(value);
-          break;
-        case 'D':
-          rv = GetAnniversaryDay(value);
-          break;
-        default:
-      rv = NS_ERROR_UNEXPECTED;
-      break;
-      }
-      break;
-    case 'B':
-      // BirthYear, BirthMonth, BirthDay
-      switch (attrname[5]) {
-        case 'Y':
-          rv = GetBirthYear(value);
-          break;
-        case 'M':
-          rv = GetBirthMonth(value);
-          break;
-        case 'D':
-          rv = GetBirthDay(value);
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'C':
-      switch (attrname[1]) {
-        case 'o':
-          rv = GetCompany(value);
-          break;
-        case 'a': // Category
-          rv = GetCategory(value);
-          break;
-        case 'e':
-          if (strlen(attrname) <= 14)
-          rv = GetCellularNumber(value);
-          else
-            rv = GetCellularNumberType(value);
-          break;
-        case 'u':
-          switch (attrname[6]) {
-            case '1':
-              rv = GetCustom1(value);
-              break;
-            case '2':
-              rv = GetCustom2(value);
-              break;
-            case '3':
-              rv = GetCustom3(value);
-              break;
-            case '4':
-              rv = GetCustom4(value);
-              break;
-            default:
-              rv = NS_ERROR_UNEXPECTED;
-              break;
-          }
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'D':
-      if (attrname[1] == 'i')
-        rv = GetDisplayName(value);
-      else if (attrname[2] == 'f')
-        rv = GetDefaultAddress(value);
-      else
-        rv = GetDepartment(value);
-      break;
-    case 'F':
-      switch (attrname[1]) {
-      case 'i':
-        rv = GetFirstName(value);
-        break;
-      case 'a':
-        if ((attrname[2] == 'x'))
-          if (strlen(attrname) <= 9)
-        rv = GetFaxNumber(value);
-          else
-            rv = GetFaxNumberType(value);
-        else
-          rv = GetFamilyName(value);
-        break;
-      default:
-        rv = NS_ERROR_UNEXPECTED;
-        break;
-      }
-      break;
-    case 'H':
-      switch (attrname[4]) {
-        case 'A':
-          if (attrname[11] == '\0')
-            rv = GetHomeAddress(value);
-          else
-            rv = GetHomeAddress2(value);
-          break;
-        case 'C':
-          if (attrname[5] == 'i')
-            rv = GetHomeCity(value);
-          else
-            rv = GetHomeCountry(value);
-          break;
-        case 'P':
-          if (strlen(attrname) <= 9)
-          rv = GetHomePhone(value);
-          else
-            rv = GetHomePhoneType(value);
-          break;
-        case 'S':
-          rv = GetHomeState(value);
-          break;
-        case 'Z':
-          rv = GetHomeZipCode(value);
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'J':
-      rv = GetJobTitle(value);
-      break;
-    case 'L':
-      if (attrname[1] == 'a') {
-        if (attrname[4] == 'N')
-          rv = GetLastName(value);
-        else {
-          // XXX todo
-          // fix me?  LDAP code gets here
-          PRUint32 lastModifiedDate;
-          rv = GetLastModifiedDate(&lastModifiedDate);
-          value.AssignLiteral("0Z");
-        }
-      }
-      else
-        rv = NS_ERROR_UNEXPECTED;
-      break;
-    case 'N':
-      if (attrname[1] == 'o')
-        rv = GetNotes(value);
-      else
-        rv = GetNickName(value);
-      break;
-    case 'P':
-      switch (attrname[2]) {
-        case 'e':
-        {
-          PRUint32 format;
-          rv = GetPreferMailFormat(&format);
+NS_IMETHODIMP nsAbCardProperty::GetPropertyAsAUTF8String(const char *name, nsACString &value) 
+{
+  nsCOMPtr<nsIVariant> variant;
+  return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ?
+    variant->GetAsAUTF8String(value) : NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP nsAbCardProperty::GetPropertyAsUint32(const char *name, PRUint32 *value) 
+{
+  nsCOMPtr<nsIVariant> variant;
+  return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ?
+    variant->GetAsUint32(value) : NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP nsAbCardProperty::GetPropertyAsBool(const char *name, PRBool *value) 
+{
+  nsCOMPtr<nsIVariant> variant;
+  return m_properties.Get(nsDependentCString(name), getter_AddRefs(variant)) ?
+    variant->GetAsBool(value) : NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP nsAbCardProperty::SetProperty(const nsACString &name, nsIVariant *value)
+{
+  return m_properties.Put(name, value);
+}
+
+NS_IMETHODIMP nsAbCardProperty::SetPropertyAsAString(const char *name, const nsAString &value) 
+{
+  nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
+  variant->SetAsAString(value);
+  return m_properties.Put(nsDependentCString(name), variant);
+}
 
-          switch (format) {
-            case nsIAbPreferMailFormat::html:
-              value.AssignLiteral("html");
-              break;
-            case nsIAbPreferMailFormat::plaintext:
-              value.AssignLiteral("plaintext");
-              break;
-            case nsIAbPreferMailFormat::unknown:
-            default :
-              value.AssignLiteral("unknown");
-              break;
-          }
-          break;
-        }
-        case 'g':
-          if (strlen(attrname) <= 11)
-          rv = GetPagerNumber(value);
-          else
-            rv = GetPagerNumberType(value);
-          break;
-        case 'i':
-          rv = GetPrimaryEmail(value);
-          break;
-        case 'o':
-          if (attrname[8] == 'L')
-            rv = GetPhoneticLastName(value);
-          else if (attrname[8] == 'F')
-            rv = GetPhoneticFirstName(value);
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'S':
-      if (attrname[1] == 'e')
-      rv = GetSecondEmail(value);
-      else
-        rv = GetSpouseName(value);
-      break;
-    case 'W':
-      if (attrname[1] == 'e') {
-        if (attrname[7] == '1')
-          rv = GetWebPage1(value);
-        else
-          rv = GetWebPage2(value);
-      }
-      else {
-        switch (attrname[4]) {
-          case 'A':
-            if (attrname[11] == '\0')
-              rv = GetWorkAddress(value);
-            else
-              rv = GetWorkAddress2(value);
-            break;
-          case 'C':
-            if (attrname[5] == 'i')
-              rv = GetWorkCity(value);
-            else
-              rv = GetWorkCountry(value);
-            break;
-          case 'P':
-            if (strlen(attrname) <= 9)
-            rv = GetWorkPhone(value);
-            else
-              rv = GetWorkPhoneType(value);
-            break;
-          case 'S':
-            rv = GetWorkState(value);
-            break;
-          case 'Z':
-            rv = GetWorkZipCode(value);
-            break;
-          default:
-            rv = NS_ERROR_UNEXPECTED;
-            break;
-        }
-      }
-      break;
-    default:
-      rv = NS_ERROR_UNEXPECTED;
-      break;
+NS_IMETHODIMP nsAbCardProperty::SetPropertyAsAUTF8String(const char *name, const nsACString &value) 
+{
+  nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
+  variant->SetAsAUTF8String(value);
+  return m_properties.Put(nsDependentCString(name), variant);
+}
+
+NS_IMETHODIMP nsAbCardProperty::SetPropertyAsUint32(const char *name, PRUint32 value) 
+{
+  nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
+  variant->SetAsUint32(value);
+  return m_properties.Put(nsDependentCString(name), variant);
+}
+
+NS_IMETHODIMP nsAbCardProperty::SetPropertyAsBool(const char *name, PRBool value) 
+{
+  nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance(NS_VARIANT_CONTRACTID);
+  variant->SetAsBool(value);
+  return m_properties.Put(nsDependentCString(name), variant);
+}
+
+NS_IMETHODIMP nsAbCardProperty::DeleteProperty(const nsACString &name)
+{
+  m_properties.Remove(name);
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsAbCardProperty::GetFirstName(nsAString &aString)
+{
+  nsresult rv = GetPropertyAsAString(kFirstNameProperty, aString);
+  if (rv == NS_ERROR_NOT_AVAILABLE)
+  {
+    aString.Truncate();
+    return NS_OK;
   }
-
-  // don't assert here, as failure is expected in certain cases
-  // we call GetCardValue() from nsAbView::Init() to determine if the
-  // saved sortColumn is valid or not.
   return rv;
 }
 
-NS_IMETHODIMP nsAbCardProperty::SetCardValue(const char *attrname, const nsAString &value)
+NS_IMETHODIMP nsAbCardProperty::SetFirstName(const nsAString &aString)
 {
-  NS_ENSURE_ARG_POINTER(attrname);
-
-  nsresult rv = NS_OK;
+  return SetPropertyAsAString(kFirstNameProperty, aString);
+}
 
-  switch (attrname[0]) {
-    case '_': // _AimScreenName
-      rv = SetAimScreenName(value);
-      break;
-    case 'A':
-      // AllowRemoteContent, AnniversaryYear, AnniversaryMonth, AnniversaryDay
-      switch (attrname[11]) {
-        case 'C':
-            SetAllowRemoteContent(value.First() == 't' || value.First() == 'T');
-          break;
-        case 'Y':
-          rv = SetAnniversaryYear(value);
-          break;
-        case 'M':
-          rv = SetAnniversaryMonth(value);
-          break;
-        case 'D':
-          rv = SetAnniversaryDay(value);
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'B':
-      // BirthYear, BirthMonth, BirthDay
-      switch (attrname[5]) {
-        case 'Y':
-          rv = SetBirthYear(value);
-          break;
-        case 'M':
-          rv = SetBirthMonth(value);
-          break;
-        case 'D':
-          rv = SetBirthDay(value);
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'C':
-      switch (attrname[1]) {
-        case 'o':
-          rv = SetCompany(value);
-          break;
-        case 'a': // Category
-          rv = SetCategory(value);
-          break;
-        case 'e':
-          if (strlen(attrname) <= 14)
-          rv = SetCellularNumber(value);
-          else
-            rv = SetCellularNumberType(value);
-          break;
-        case 'u':
-          switch (attrname[6]) {
-            case '1':
-              rv = SetCustom1(value);
-              break;
-            case '2':
-              rv = SetCustom2(value);
-              break;
-            case '3':
-              rv = SetCustom3(value);
-              break;
-            case '4':
-              rv = SetCustom4(value);
-              break;
-            default:
-              rv = NS_ERROR_UNEXPECTED;
-              break;
-          }
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'D':
-      if (attrname[1] == 'i')
-        rv = SetDisplayName(value);
-      else if (attrname[2] == 'f')
-        rv = SetDefaultAddress(value);
-      else
-        rv = SetDepartment(value);
-      break;
-    case 'F':
-      switch (attrname[1]) {
-      case 'i':
-        rv = SetFirstName(value);
-        break;
-      case 'a':
-        if ((attrname[2] == 'x'))
-          if (strlen(attrname) <= 9)
-        rv = SetFaxNumber(value);
-          else
-            rv = SetFaxNumberType(value);
-        else
-          rv = SetFamilyName(value);
-        break;
-      default:
-        rv = NS_ERROR_UNEXPECTED;
-        break;
-      }
-      break;
-    case 'H':
-      switch (attrname[4]) {
-        case 'A':
-          if (attrname[11] == '\0')
-            rv = SetHomeAddress(value);
-          else
-            rv = SetHomeAddress2(value);
-          break;
-        case 'C':
-          if (attrname[5] == 'i')
-            rv = SetHomeCity(value);
-          else
-            rv = SetHomeCountry(value);
-          break;
-        case 'P':
-          if (strlen(attrname) <= 9)
-          rv = SetHomePhone(value);
-          else
-            rv = SetHomePhoneType(value);
-          break;
-        case 'S':
-          rv = SetHomeState(value);
-          break;
-        case 'Z':
-          rv = SetHomeZipCode(value);
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'J':
-      rv = SetJobTitle(value);
-      break;
-    case 'L':
-      if (attrname[1] == 'a') {
-        if (attrname[4] == 'N')
-          rv = SetLastName(value);
-        else {
-          // XXX todo
-          // fix me?  LDAP code gets here
-          rv = SetLastModifiedDate(0);
-        }
-      }
-      else
-        rv = NS_ERROR_UNEXPECTED;
-      break;
-    case 'N':
-      if (attrname[1] == 'o')
-        rv = SetNotes(value);
-      else
-        rv = SetNickName(value);
-      break;
-    case 'P':
-      switch (attrname[2]) {
-        case 'e':
-          switch (value.First()) {
-            case 't':    // "true"
-            case 'T':
-              rv = SetPreferMailFormat(nsIAbPreferMailFormat::html);
-              break;
-            case 'f':    // "false"
-            case 'F':
-              rv = SetPreferMailFormat(nsIAbPreferMailFormat::plaintext);
-              break;
-            default:
-              rv = SetPreferMailFormat(nsIAbPreferMailFormat::unknown);
-              break;
-          }
-          break;
-        case 'g':
-          if (strlen(attrname) <= 11)
-          rv = SetPagerNumber(value);
-          else
-            rv = SetPagerNumberType(value);
-          break;
-        case 'i':
-          rv = SetPrimaryEmail(value);
-          break;
-        case 'o':
-          if (attrname[8] == 'L')
-            rv = SetPhoneticLastName(value);
-          else if (attrname[8] == 'F')
-            rv = SetPhoneticFirstName(value);
-          break;
-        default:
-          rv = NS_ERROR_UNEXPECTED;
-          break;
-      }
-      break;
-    case 'S':
-      if (attrname[1] == 'e')
-      rv = SetSecondEmail(value);
-      else
-        rv = SetSpouseName(value);
-      break;
-    case 'W':
-      if (attrname[1] == 'e') {
-        if (attrname[7] == '1')
-          rv = SetWebPage1(value);
-        else
-          rv = SetWebPage2(value);
-      }
-      else {
-        switch (attrname[4]) {
-          case 'A':
-            if (attrname[11] == '\0')
-              rv = SetWorkAddress(value);
-            else
-              rv = SetWorkAddress2(value);
-            break;
-          case 'C':
-            if (attrname[5] == 'i')
-              rv = SetWorkCity(value);
-            else
-              rv = SetWorkCountry(value);
-            break;
-          case 'P':
-            if (strlen(attrname) <= 9)
-            rv = SetWorkPhone(value);
-            else
-              rv = SetWorkPhoneType(value);
-            break;
-          case 'S':
-            rv = SetWorkState(value);
-            break;
-          case 'Z':
-            rv = SetWorkZipCode(value);
-            break;
-          default:
-            rv = NS_ERROR_UNEXPECTED;
-            break;
-        }
-      }
-      break;
-    default:
-      rv = NS_ERROR_UNEXPECTED;
-      break;
+NS_IMETHODIMP nsAbCardProperty::GetLastName(nsAString &aString)
+{
+  nsresult rv = GetPropertyAsAString(kLastNameProperty, aString);
+  if (rv == NS_ERROR_NOT_AVAILABLE)
+  {
+    aString.Truncate();
+    return NS_OK;
   }
-
-  NS_ENSURE_SUCCESS(rv,rv);
   return rv;
 }
 
-NS_IMETHODIMP
-nsAbCardProperty::GetLastModifiedDate(PRUint32 *aLastModifiedDate)
+NS_IMETHODIMP nsAbCardProperty::SetLastName(const nsAString &aString)
 {
-  *aLastModifiedDate = m_LastModDate;
-  return NS_OK;
+  return SetPropertyAsAString(kLastNameProperty, aString);
 }
 
-NS_IMETHODIMP
-nsAbCardProperty::SetLastModifiedDate(PRUint32 aLastModifiedDate)
+NS_IMETHODIMP nsAbCardProperty::GetDisplayName(nsAString &aString)
 {
-  m_LastModDate = aLastModifiedDate;
-  return NS_OK;
-}
-
-#define GET_SET_STR_ATTR(_method, _member)                             \
-NS_IMETHODIMP nsAbCardProperty::Get##_method(nsAString &aString)       \
-{                                                                      \
-  aString = _member;                                                   \
-  return NS_OK;                                                        \
-}                                                                      \
-NS_IMETHODIMP nsAbCardProperty::Set##_method(const nsAString &aString) \
-{                                                                      \
-  _member = aString;                                                   \
- return NS_OK;                                                         \
+  nsresult rv = GetPropertyAsAString(kDisplayNameProperty, aString);
+  if (rv == NS_ERROR_NOT_AVAILABLE)
+  {
+    aString.Truncate();
+    return NS_OK;
+  }
+  return rv;
 }
 
-GET_SET_STR_ATTR(FirstName, m_FirstName)
-GET_SET_STR_ATTR(LastName, m_LastName)
-GET_SET_STR_ATTR(PhoneticFirstName, m_PhoneticFirstName)
-GET_SET_STR_ATTR(PhoneticLastName, m_PhoneticLastName)
-GET_SET_STR_ATTR(DisplayName, m_DisplayName)
-GET_SET_STR_ATTR(NickName, m_NickName)
-GET_SET_STR_ATTR(PrimaryEmail, m_PrimaryEmail)
-GET_SET_STR_ATTR(SecondEmail, m_SecondEmail)
-GET_SET_STR_ATTR(WorkPhone, m_WorkPhone)
-GET_SET_STR_ATTR(HomePhone, m_HomePhone)
-GET_SET_STR_ATTR(FaxNumber, m_FaxNumber)
-GET_SET_STR_ATTR(PagerNumber, m_PagerNumber)
-GET_SET_STR_ATTR(CellularNumber, m_CellularNumber)
-GET_SET_STR_ATTR(WorkPhoneType, m_WorkPhoneType)
-GET_SET_STR_ATTR(HomePhoneType, m_HomePhoneType)
-GET_SET_STR_ATTR(FaxNumberType, m_FaxNumberType)
-GET_SET_STR_ATTR(PagerNumberType, m_PagerNumberType)
-GET_SET_STR_ATTR(CellularNumberType, m_CellularNumberType)
-GET_SET_STR_ATTR(HomeAddress, m_HomeAddress)
-GET_SET_STR_ATTR(HomeAddress2, m_HomeAddress2)
-GET_SET_STR_ATTR(HomeCity, m_HomeCity)
-GET_SET_STR_ATTR(HomeState, m_HomeState)
-GET_SET_STR_ATTR(HomeZipCode, m_HomeZipCode)
-GET_SET_STR_ATTR(HomeCountry, m_HomeCountry)
-GET_SET_STR_ATTR(WorkAddress, m_WorkAddress)
-GET_SET_STR_ATTR(WorkAddress2, m_WorkAddress2)
-GET_SET_STR_ATTR(WorkCity, m_WorkCity)
-GET_SET_STR_ATTR(WorkState, m_WorkState)
-GET_SET_STR_ATTR(WorkZipCode, m_WorkZipCode)
-GET_SET_STR_ATTR(WorkCountry, m_WorkCountry)
-GET_SET_STR_ATTR(JobTitle, m_JobTitle)
-GET_SET_STR_ATTR(Department, m_Department)
-GET_SET_STR_ATTR(Company, m_Company)
-GET_SET_STR_ATTR(AimScreenName, m_AimScreenName)
-GET_SET_STR_ATTR(AnniversaryYear, m_AnniversaryYear)
-GET_SET_STR_ATTR(AnniversaryMonth, m_AnniversaryMonth)
-GET_SET_STR_ATTR(AnniversaryDay, m_AnniversaryDay)
-GET_SET_STR_ATTR(SpouseName, m_SpouseName)
-GET_SET_STR_ATTR(FamilyName, m_FamilyName)
-GET_SET_STR_ATTR(DefaultAddress, m_DefaultAddress)
-GET_SET_STR_ATTR(Category, m_Category)
-GET_SET_STR_ATTR(WebPage1, m_WebPage1)
-GET_SET_STR_ATTR(WebPage2, m_WebPage2)
-GET_SET_STR_ATTR(BirthYear, m_BirthYear)
-GET_SET_STR_ATTR(BirthMonth, m_BirthMonth)
-GET_SET_STR_ATTR(BirthDay, m_BirthDay)
-GET_SET_STR_ATTR(Custom1, m_Custom1)
-GET_SET_STR_ATTR(Custom2, m_Custom2)
-GET_SET_STR_ATTR(Custom3, m_Custom3)
-GET_SET_STR_ATTR(Custom4, m_Custom4)
-GET_SET_STR_ATTR(Notes, m_Note)
+NS_IMETHODIMP nsAbCardProperty::SetDisplayName(const nsAString &aString)
+{
+  return SetPropertyAsAString(kDisplayNameProperty, aString);
+}
+
+NS_IMETHODIMP nsAbCardProperty::GetPrimaryEmail(nsAString &aString)
+{
+  nsresult rv = GetPropertyAsAString(kPriEmailProperty, aString);
+  if (rv == NS_ERROR_NOT_AVAILABLE)
+  {
+    aString.Truncate();
+    return NS_OK;
+  }
+  return rv;
+}
+
+NS_IMETHODIMP nsAbCardProperty::SetPrimaryEmail(const nsAString &aString)
+{
+  return SetPropertyAsAString(kPriEmailProperty, aString);
+}
 
 // This function may be overriden by derived classes for
 // nsAb*Card specific implementations.
 NS_IMETHODIMP nsAbCardProperty::Copy(nsIAbCard* srcCard)
 {
   NS_ENSURE_ARG_POINTER(srcCard);
 
-  nsString str;
-  srcCard->GetFirstName(str);
-  SetFirstName(str);
+  nsCOMPtr<nsISimpleEnumerator> properties;
+  nsresult rv = srcCard->GetProperties(getter_AddRefs(properties));
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  srcCard->GetLastName(str);
-  SetLastName(str);
-  srcCard->GetPhoneticFirstName(str);
-  SetPhoneticFirstName(str);
-  srcCard->GetPhoneticLastName(str);
-  SetPhoneticLastName(str);
-  srcCard->GetDisplayName(str);
-  SetDisplayName(str);
-  srcCard->GetNickName(str);
-  SetNickName(str);
-  srcCard->GetPrimaryEmail(str);
-  SetPrimaryEmail(str);
-  srcCard->GetSecondEmail(str);
-  SetSecondEmail(str);
-
-  PRUint32 format = nsIAbPreferMailFormat::unknown;
-  srcCard->GetPreferMailFormat(&format);
-  SetPreferMailFormat(format);
-
-  PRUint32 popularityIndex = 0;
-  srcCard->GetPopularityIndex(&popularityIndex);
-  SetPopularityIndex(popularityIndex);
-
-  PRBool allowRemoteContent = PR_FALSE;
-  srcCard->GetAllowRemoteContent(&allowRemoteContent);
-  SetAllowRemoteContent(allowRemoteContent);
+  PRBool hasMore;
+  nsCOMPtr<nsISupports> result;
+  while (NS_SUCCEEDED(rv = properties->HasMoreElements(&hasMore)) && hasMore)
+  {
+    rv = properties->GetNext(getter_AddRefs(result));
+    NS_ENSURE_SUCCESS(rv, rv);
 
-  srcCard->GetWorkPhone(str);
-  SetWorkPhone(str);
-  srcCard->GetHomePhone(str);
-  SetHomePhone(str);
-  srcCard->GetFaxNumber(str);
-  SetFaxNumber(str);
-  srcCard->GetPagerNumber(str);
-  SetPagerNumber(str);
-  srcCard->GetCellularNumber(str);
-  SetCellularNumber(str);
-  srcCard->GetWorkPhoneType(str);
-  SetWorkPhoneType(str);
-  srcCard->GetHomePhoneType(str);
-  SetHomePhoneType(str);
-  srcCard->GetFaxNumberType(str);
-  SetFaxNumberType(str);
-  srcCard->GetPagerNumberType(str);
-  SetPagerNumberType(str);
-  srcCard->GetCellularNumberType(str);
-  SetCellularNumberType(str);
-  srcCard->GetHomeAddress(str);
-  SetHomeAddress(str);
-  srcCard->GetHomeAddress2(str);
-  SetHomeAddress2(str);
-  srcCard->GetHomeCity(str);
-  SetHomeCity(str);
-  srcCard->GetHomeState(str);
-  SetHomeState(str);
-  srcCard->GetHomeZipCode(str);
-  SetHomeZipCode(str);
-  srcCard->GetHomeCountry(str);
-  SetHomeCountry(str);
-  srcCard->GetWorkAddress(str);
-  SetWorkAddress(str);
-  srcCard->GetWorkAddress2(str);
-  SetWorkAddress2(str);
-  srcCard->GetWorkCity(str);
-  SetWorkCity(str);
-  srcCard->GetWorkState(str);
-  SetWorkState(str);
-  srcCard->GetWorkZipCode(str);
-  SetWorkZipCode(str);
-  srcCard->GetWorkCountry(str);
-  SetWorkCountry(str);
-  srcCard->GetJobTitle(str);
-  SetJobTitle(str);
-  srcCard->GetDepartment(str);
-  SetDepartment(str);
-  srcCard->GetCompany(str);
-  SetCompany(str);
-  srcCard->GetAimScreenName(str);
-  SetAimScreenName(str);
+    nsCOMPtr<nsIProperty> property = do_QueryInterface(result, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-  srcCard->GetAnniversaryYear(str);
-  SetAnniversaryYear(str);
-  srcCard->GetAnniversaryMonth(str);
-  SetAnniversaryMonth(str);
-  srcCard->GetAnniversaryDay(str);
-  SetAnniversaryDay(str);
-  srcCard->GetSpouseName(str);
-  SetSpouseName(str);
-  srcCard->GetFamilyName(str);
-  SetFamilyName(str);
-  srcCard->GetDefaultAddress(str);
-  SetDefaultAddress(str);
-  srcCard->GetCategory(str);
-  SetCategory(str);
+    nsAutoString name;
+    property->GetName(name);
+    nsCOMPtr<nsIVariant> value;
+    property->GetValue(getter_AddRefs(value));
 
-  srcCard->GetWebPage1(str);
-  SetWebPage1(str);
-  srcCard->GetWebPage2(str);
-  SetWebPage2(str);
-  srcCard->GetBirthYear(str);
-  SetBirthYear(str);
-  srcCard->GetBirthMonth(str);
-  SetBirthMonth(str);
-  srcCard->GetBirthDay(str);
-  SetBirthDay(str);
-  srcCard->GetCustom1(str);
-  SetCustom1(str);
-  srcCard->GetCustom2(str);
-  SetCustom2(str);
-  srcCard->GetCustom3(str);
-  SetCustom3(str);
-  srcCard->GetCustom4(str);
-  SetCustom4(str);
-  srcCard->GetNotes(str);
-  SetNotes(str);
+    SetProperty(NS_ConvertUTF16toUTF8(name), value);
+  }
+  NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool isMailList;
   srcCard->GetIsMailList(&isMailList);
   SetIsMailList(isMailList);
 
   nsCString mailListURI;
   srcCard->GetMailListURI(getter_Copies(mailListURI));
   SetMailListURI(mailListURI.get());
@@ -949,26 +407,50 @@ NS_IMETHODIMP nsAbCardProperty::Copy(nsI
 }
 
 NS_IMETHODIMP nsAbCardProperty::Equals(nsIAbCard *card, PRBool *result)
 {
   *result = (card == this);
   return NS_OK;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// The following methods are other views of a card
+////////////////////////////////////////////////////////////////////////////////
+
+// XXX: Use the category manager instead of this file to implement these
+NS_IMETHODIMP nsAbCardProperty::TranslateTo(const nsACString &type, nsACString &result)
+{
+  if (type.EqualsLiteral("base64"))
+    return ConvertToBase64EncodedXML(result);
+  else if (type.EqualsLiteral("xml"))
+  {
+    nsString utf16String;
+    nsresult rv = ConvertToXMLPrintData(utf16String);
+    NS_ENSURE_SUCCESS(rv, rv);
+    result = NS_ConvertUTF16toUTF8(utf16String);
+    return NS_OK;
+  }
+  else if (type.EqualsLiteral("vcard"))
+    return ConvertToEscapedVCard(result);
+
+  return NS_ERROR_ILLEGAL_VALUE;
+}
+//
 static VObject* myAddPropValue(VObject *o, const char *propName, const PRUnichar *propValue, PRBool *aCardHasData)
 {
     if (aCardHasData)
         *aCardHasData = PR_TRUE;
     return addPropValue(o, propName, NS_ConvertUTF16toUTF8(propValue).get());
 }
 
-NS_IMETHODIMP nsAbCardProperty::ConvertToEscapedVCard(char **aResult)
+nsresult nsAbCardProperty::ConvertToEscapedVCard(nsACString &aResult)
 {
     nsString str;
+    nsresult rv;
     PRBool vCardHasData = PR_FALSE;
     VObject* vObj = newVObject(VCCardProp);
     VObject* t;
 
     // [comment from 4.x]
     // Big flame coming....so Vobject is not designed at all to work with  an array of
     // attribute values. It wants you to have all of the attributes easily available. You
     // cannot add one attribute at a time as you find them to the vobject. Why? Because
@@ -995,81 +477,81 @@ NS_IMETHODIMP nsAbCardProperty::ConvertT
     (void)GetFirstName(str);
     if (!str.IsEmpty()) {
         t = isAPropertyOf(vObj, VCNameProp);
         if (!t)
             t = addProp(vObj, VCNameProp);
         myAddPropValue(t, VCGivenNameProp, str.get(), &vCardHasData);
     }
 
-    (void)GetCompany(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kCompanyProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCOrgProp);
         if (!t)
             t = addProp(vObj, VCOrgProp);
         myAddPropValue(t, VCOrgNameProp, str.get(), &vCardHasData);
     }
 
-    (void)GetDepartment(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kDepartmentProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCOrgProp);
         if (!t)
             t = addProp(vObj, VCOrgProp);
         myAddPropValue(t, VCOrgUnitProp, str.get(), &vCardHasData);
     }
 
-    (void)GetWorkAddress2(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkAddress2Property, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCAdrProp);
         if  (!t)
             t = addProp(vObj, VCAdrProp);
         myAddPropValue(t, VCPostalBoxProp, str.get(), &vCardHasData);
     }
 
-    (void)GetWorkAddress(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkAddressProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCAdrProp);
         if  (!t)
             t = addProp(vObj, VCAdrProp);
         myAddPropValue(t, VCStreetAddressProp, str.get(), &vCardHasData);
     }
 
-    (void)GetWorkCity(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkCityProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCAdrProp);
         if  (!t)
             t = addProp(vObj, VCAdrProp);
         myAddPropValue(t, VCCityProp, str.get(), &vCardHasData);
     }
 
-    (void)GetWorkState(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkStateProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCAdrProp);
         if  (!t)
             t = addProp(vObj, VCAdrProp);
         myAddPropValue(t, VCRegionProp, str.get(), &vCardHasData);
     }
 
-    (void)GetWorkZipCode(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkZipCodeProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCAdrProp);
         if  (!t)
             t = addProp(vObj, VCAdrProp);
         myAddPropValue(t, VCPostalCodeProp, str.get(), &vCardHasData);
     }
 
-    (void)GetWorkCountry(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkCountryProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = isAPropertyOf(vObj, VCAdrProp);
         if  (!t)
             t = addProp(vObj, VCAdrProp);
         myAddPropValue(t, VCCountryNameProp, str.get(), &vCardHasData);
     }
     else
     {
@@ -1077,103 +559,103 @@ NS_IMETHODIMP nsAbCardProperty::ConvertT
         t = isAPropertyOf(vObj, VCAdrProp);
         if (t)
         {
             addProp(t, VCDomesticProp);
         }
     }
 
     (void)GetPrimaryEmail(str);
-    if (!str.IsEmpty())
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = myAddPropValue(vObj, VCEmailAddressProp, str.get(), &vCardHasData);
         addProp(t, VCInternetProp);
     }
 
-    (void)GetJobTitle(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kJobTitleProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         myAddPropValue(vObj, VCTitleProp, str.get(), &vCardHasData);
     }
 
-    (void)GetWorkPhone(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkPhoneProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = myAddPropValue(vObj, VCTelephoneProp, str.get(), &vCardHasData);
         addProp(t, VCWorkProp);
     }
 
-    (void)GetFaxNumber(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kFaxProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = myAddPropValue(vObj, VCTelephoneProp, str.get(), &vCardHasData);
         addProp(t, VCFaxProp);
     }
 
-    (void)GetPagerNumber(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kPagerProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = myAddPropValue(vObj, VCTelephoneProp, str.get(), &vCardHasData);
         addProp(t, VCPagerProp);
     }
 
-    (void)GetHomePhone(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kHomePhoneProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = myAddPropValue(vObj, VCTelephoneProp, str.get(), &vCardHasData);
         addProp(t, VCHomeProp);
     }
 
-    (void)GetCellularNumber(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kCellularProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         t = myAddPropValue(vObj, VCTelephoneProp, str.get(), &vCardHasData);
         addProp(t, VCCellularProp);
     }
 
-    (void)GetNotes(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kNotesProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         myAddPropValue(vObj, VCNoteProp, str.get(), &vCardHasData);
     }
 
     PRUint32 format;
-    (void)GetPreferMailFormat(&format);
-    if (format == nsIAbPreferMailFormat::html) {
+    rv = GetPropertyAsUint32(kPreferMailFormatProperty, &format);
+    if (NS_SUCCEEDED(rv) && format == nsIAbPreferMailFormat::html) {
         myAddPropValue(vObj, VCUseHTML, NS_LITERAL_STRING("TRUE").get(), &vCardHasData);
     }
-    else if (format == nsIAbPreferMailFormat::plaintext) {
+    else if (NS_SUCCEEDED(rv) && format == nsIAbPreferMailFormat::plaintext) {
         myAddPropValue(vObj, VCUseHTML, NS_LITERAL_STRING("FALSE").get(), &vCardHasData);
     }
 
-    (void)GetWebPage1(str);
-    if (!str.IsEmpty())
+    rv = GetPropertyAsAString(kWorkWebPageProperty, str);
+    if (NS_SUCCEEDED(rv) && !str.IsEmpty())
     {
         myAddPropValue(vObj, VCURLProp, str.get(), &vCardHasData);
     }
 
     myAddPropValue(vObj, VCVersionProp, NS_LITERAL_STRING("2.1").get(), nsnull);
 
     if (!vCardHasData) {
-        *aResult = PL_strdup("");
+        aResult.Truncate();
         return NS_OK;
     }
 
     int len = 0;
     char *vCard = writeMemVObject(0, &len, vObj);
     if (vObj)
         cleanVObject(vObj);
 
     nsCString escResult;
     MsgEscapeString(nsDependentCString(vCard), nsINetUtil::ESCAPE_URL_PATH, escResult);
-    *aResult = strdup(escResult.get());
-    return (*aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
+    aResult = escResult;
+    return NS_OK;
 }
 
-NS_IMETHODIMP nsAbCardProperty::ConvertToBase64EncodedXML(char **result)
+nsresult nsAbCardProperty::ConvertToBase64EncodedXML(nsACString &result)
 {
   nsresult rv;
   nsString xmlStr;
 
   xmlStr.AppendLiteral("<?xml version=\"1.0\"?>\n"
                        "<?xml-stylesheet type=\"text/css\" href=\"chrome://messenger/content/addressbook/print.css\"?>\n"
                        "<directory>\n");
 
@@ -1195,21 +677,21 @@ NS_IMETHODIMP nsAbCardProperty::ConvertT
 
   nsString xmlSubstr;
   rv = ConvertToXMLPrintData(xmlSubstr);
   NS_ENSURE_SUCCESS(rv,rv);
 
   xmlStr.Append(xmlSubstr);
   xmlStr.AppendLiteral("</directory>\n");
 
-  *result = PL_Base64Encode(NS_ConvertUTF16toUTF8(xmlStr).get(), 0, nsnull);
-  return (*result ? NS_OK : NS_ERROR_OUT_OF_MEMORY);
+  result.Adopt(PL_Base64Encode(NS_ConvertUTF16toUTF8(xmlStr).get(), 0, nsnull));
+  return NS_OK;
 }
 
-NS_IMETHODIMP nsAbCardProperty::ConvertToXMLPrintData(nsAString &aXMLSubstr)
+nsresult nsAbCardProperty::ConvertToXMLPrintData(nsAString &aXMLSubstr)
 {
   nsresult rv;
   nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv,rv);
 
   PRInt32 generatedNameFormat;
   rv = prefBranch->GetIntPref(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST, &generatedNameFormat);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1237,18 +719,17 @@ NS_IMETHODIMP nsAbCardProperty::ConvertT
   if (!generatedName.IsEmpty()) {
     rv = conv->ScanTXT(generatedName.get(), mozITXTToHTMLConv::kEntities,
                        getter_Copies(safeText));
     NS_ENSURE_SUCCESS(rv,rv);
   }
 
   if (safeText.IsEmpty()) {
     nsAutoString primaryEmail;
-    rv = GetCardValue(kPriEmailColumn, primaryEmail);
-    NS_ENSURE_SUCCESS(rv,rv);
+    GetPrimaryEmail(primaryEmail);
 
     // use ScanTXT to convert < > & to safe values.
     rv = conv->ScanTXT(primaryEmail.get(), mozITXTToHTMLConv::kEntities,
                        getter_Copies(safeText));
     NS_ENSURE_SUCCESS(rv,rv);
   }
   xmlStr.Append(safeText);
 
@@ -1309,18 +790,17 @@ NS_IMETHODIMP nsAbCardProperty::ConvertT
           nsString safeText;
           rv = conv->ScanTXT(displayName.get(), mozITXTToHTMLConv::kEntities,
                              getter_Copies(safeText));
           NS_ENSURE_SUCCESS(rv,rv);
           xmlStr.Append(safeText);
 
           xmlStr.AppendLiteral(" &lt;");
 
-          rv = listCard->GetPrimaryEmail(primaryEmail);
-          NS_ENSURE_SUCCESS(rv,rv);
+          listCard->GetPrimaryEmail(primaryEmail);
 
           // use ScanTXT to convert < > & to safe values.
           rv = conv->ScanTXT(primaryEmail.get(), mozITXTToHTMLConv::kEntities,
                              getter_Copies(safeText));
           NS_ENSURE_SUCCESS(rv,rv);
           xmlStr.Append(safeText);
 
           xmlStr.AppendLiteral("&gt;</PrimaryEmail>\n");
@@ -1337,59 +817,33 @@ NS_IMETHODIMP nsAbCardProperty::ConvertT
 
   xmlStr.AppendLiteral("</td></tr></table>");
 
   aXMLSubstr = xmlStr;
 
   return NS_OK;
 }
 
-nsresult nsAbCardProperty::AppendData(const char *aAttrName, mozITXTToHTMLConv *aConv, nsString &aResult)
-{
-  nsString attrValue;
-  nsresult rv = GetCardValue(aAttrName, attrValue);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  if (attrValue.IsEmpty())
-    return NS_OK;
-
-  aResult.Append(PRUnichar('<'));
-  aResult.Append(NS_ConvertASCIItoUTF16(aAttrName));
-  aResult.Append(PRUnichar('>'));
-
-  // use ScanTXT to convert < > & to safe values.
-  nsString safeText;
-  rv = aConv->ScanTXT(attrValue.get(), mozITXTToHTMLConv::kEntities, getter_Copies(safeText));
-  NS_ENSURE_SUCCESS(rv,rv);
-  aResult.Append(safeText);
-
-  aResult.AppendLiteral("</");
-  aResult.Append(NS_ConvertASCIItoUTF16(aAttrName));
-  aResult.Append(PRUnichar('>'));
-
-  return NS_OK;
-}
-
 nsresult nsAbCardProperty::AppendSection(const AppendItem *aArray, PRInt16 aCount, const nsString& aHeading,
                                          nsIStringBundle *aBundle,
                                          mozITXTToHTMLConv *aConv,
                                          nsString &aResult)
 {
   nsresult rv = NS_OK;
 
   aResult.AppendLiteral("<section>");
 
   nsString attrValue;
   PRBool sectionIsEmpty = PR_TRUE;
 
   PRInt16 i = 0;
   for (i=0;i<aCount;i++) {
-    rv = GetCardValue(aArray[i].mColumn, attrValue);
-    NS_ENSURE_SUCCESS(rv,rv);
-    sectionIsEmpty &= attrValue.IsEmpty();
+    rv = GetPropertyAsAString(aArray[i].mColumn, attrValue);
+    if (NS_SUCCEEDED(rv) && !attrValue.IsEmpty())
+      sectionIsEmpty = PR_FALSE;
   }
 
   if (!sectionIsEmpty && !aHeading.IsEmpty()) {
     nsString heading;
     rv = aBundle->GetStringFromName(aHeading.get(), getter_Copies(heading));
     NS_ENSURE_SUCCESS(rv, rv);
 
     aResult.AppendLiteral("<sectiontitle>");
@@ -1425,59 +879,54 @@ nsresult nsAbCardProperty::AppendSection
 
 nsresult nsAbCardProperty::AppendLine(const AppendItem &aItem,
                                       mozITXTToHTMLConv *aConv,
                                       nsString &aResult)
 {
   NS_ENSURE_ARG_POINTER(aConv);
 
   nsString attrValue;
-  nsresult rv = GetCardValue(aItem.mColumn, attrValue);
-  NS_ENSURE_SUCCESS(rv,rv);
+  nsresult rv = GetPropertyAsAString(aItem.mColumn, attrValue);
 
-  if (attrValue.IsEmpty())
+  if (NS_FAILED(rv) || attrValue.IsEmpty())
     return NS_OK;
 
   aResult.Append(PRUnichar('<'));
-  aResult.Append(NS_ConvertASCIItoUTF16(aItem.mColumn));
+  aResult.Append(NS_ConvertUTF8toUTF16(aItem.mColumn));
   aResult.Append(PRUnichar('>'));
 
   // use ScanTXT to convert < > & to safe values.
   nsString safeText;
   rv = aConv->ScanTXT(attrValue.get(), mozITXTToHTMLConv::kEntities, getter_Copies(safeText));
   NS_ENSURE_SUCCESS(rv,rv);
   aResult.Append(safeText);
 
   aResult.AppendLiteral("</");
-  aResult.Append(NS_ConvertASCIItoUTF16(aItem.mColumn));
+  aResult.Append(NS_ConvertUTF8toUTF16(aItem.mColumn));
   aResult.Append(PRUnichar('>'));
 
   return NS_OK;
 }
 
 nsresult nsAbCardProperty::AppendLabel(const AppendItem &aItem,
                                        nsIStringBundle *aBundle,
                                        mozITXTToHTMLConv *aConv,
                                        nsString &aResult)
 {
   NS_ENSURE_ARG_POINTER(aBundle);
 
   nsresult rv;
-
-  nsString label;
-
-  nsString attrValue;
+  nsString label, attrValue;
 
-  rv = GetCardValue(aItem.mColumn, attrValue);
-  NS_ENSURE_SUCCESS(rv,rv);
+  rv = GetPropertyAsAString(aItem.mColumn, attrValue);
 
-  if (attrValue.IsEmpty())
+  if (NS_FAILED(rv) || attrValue.IsEmpty())
     return NS_OK;
 
-  rv = aBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aItem.mLabel).get(), getter_Copies(label));
+  rv = aBundle->GetStringFromName(NS_ConvertUTF8toUTF16(aItem.mLabel).get(), getter_Copies(label));
   NS_ENSURE_SUCCESS(rv, rv);
 
   aResult.AppendLiteral("<labelrow><label>");
 
   aResult.Append(label);
   aResult.AppendLiteral(": </label>");
 
   rv = AppendLine(aItem, aConv, aResult);
@@ -1492,39 +941,39 @@ nsresult nsAbCardProperty::AppendCitySta
                                               nsIStringBundle *aBundle,
                                               mozITXTToHTMLConv *aConv,
                                               nsString &aResult)
 {
   NS_ENSURE_ARG_POINTER(aBundle);
 
   nsresult rv;
   AppendItem item;
-  const char *stateCol, *zipCol;
+  const char *statePropName, *zipPropName;
 
-  if (strcmp(aItem.mColumn, kHomeCityColumn) == 0) {
-    stateCol = kHomeStateColumn;
-    zipCol = kHomeZipCodeColumn;
+  if (strcmp(aItem.mColumn, kHomeCityProperty) == 0) {
+    statePropName = kHomeStateProperty;
+    zipPropName = kHomeZipCodeProperty;
   }
   else {
-    stateCol = kWorkStateColumn;
-    zipCol = kWorkZipCodeColumn;
+    statePropName = kWorkStateProperty;
+    zipPropName = kWorkZipCodeProperty;
   }
 
   nsAutoString cityResult, stateResult, zipResult;
 
   rv = AppendLine(aItem, aConv, cityResult);
   NS_ENSURE_SUCCESS(rv,rv);
 
-  item.mColumn = stateCol;
+  item.mColumn = statePropName;
   item.mLabel = "";
 
   rv = AppendLine(item, aConv, stateResult);
   NS_ENSURE_SUCCESS(rv,rv);
 
-  item.mColumn = zipCol;
+  item.mColumn = zipPropName;
 
   rv = AppendLine(item, aConv, zipResult);
   NS_ENSURE_SUCCESS(rv,rv);
 
   nsString formattedString;
 
   if (!cityResult.IsEmpty() && !stateResult.IsEmpty() && !zipResult.IsEmpty()) {
     const PRUnichar *formatStrings[] = { cityResult.get(), stateResult.get(), zipResult.get() };
@@ -1555,79 +1004,88 @@ nsresult nsAbCardProperty::AppendCitySta
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAbCardProperty::GenerateName(PRInt32 aGenerateFormat,
                                              nsIStringBundle* aBundle,
                                              nsAString &aResult)
 {
+  // Cache the first and last names
+  nsAutoString firstName, lastName;
+  GetFirstName(firstName);
+  GetLastName(lastName);
+
   // No need to check for aBundle present straight away, only do that if we're
   // actually going to use it.
-  if (aGenerateFormat == kDisplayName)
-    aResult = m_DisplayName;
-  else if (m_LastName.IsEmpty())
-    aResult = m_FirstName;
-  else if (m_FirstName.IsEmpty())
-    aResult = m_LastName;
+  if (aGenerateFormat == GENERATE_DISPLAY_NAME)
+    GetDisplayName(aResult);
+  else if (lastName.IsEmpty())
+    aResult = firstName;
+  else if (firstName.IsEmpty())
+    aResult = lastName;
   else {
     nsresult rv;
     nsCOMPtr<nsIStringBundle> bundle(aBundle);
     if (!bundle) {
       nsCOMPtr<nsIStringBundleService> stringBundleService =
         do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv); 
       NS_ENSURE_SUCCESS(rv, rv);
         
       rv = stringBundleService->CreateBundle(sAddrbookProperties,
                                              getter_AddRefs(bundle));
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     nsString result;
 
-    if (aGenerateFormat == kLastFirst) {
-      const PRUnichar *stringParams[2] = {m_LastName.get(), m_FirstName.get()};
+    if (aGenerateFormat == GENERATE_LAST_FIRST_ORDER) {
+      const PRUnichar *stringParams[2] = {lastName.get(), firstName.get()};
 
       rv = bundle->FormatStringFromName(NS_LITERAL_STRING("lastFirstFormat").get(),
                                         stringParams, 2, getter_Copies(result));
     }
     else {
-      const PRUnichar *stringParams[2] = {m_FirstName.get(), m_LastName.get()};
+      const PRUnichar *stringParams[2] = {firstName.get(), lastName.get()};
         
       rv = bundle->FormatStringFromName(NS_LITERAL_STRING("firstLastFormat").get(),
                                         stringParams, 2, getter_Copies(result));
     }
     NS_ENSURE_SUCCESS(rv, rv); 
 
     aResult.Assign(result);
   }
   
   if (aResult.IsEmpty())
   {
     // see bug #211078
     // if there is no generated name at this point
     // use the userid from the email address
     // it is better than nothing.
-    aResult = m_PrimaryEmail;
+    GetPrimaryEmail(aResult);
     PRInt32 index = aResult.FindChar('@');
     if (index != -1)
       aResult.SetLength(index);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAbCardProperty::GeneratePhoneticName(PRBool aLastNameFirst,
                                                      nsAString &aResult)
 {
+  nsAutoString firstName, lastName;
+  GetPropertyAsAString(kPhoneticFirstNameProperty, firstName);
+  GetPropertyAsAString(kPhoneticLastNameProperty, lastName);
+
   if (aLastNameFirst)
   {
-    aResult = m_PhoneticLastName;
-    aResult += m_PhoneticFirstName;
+    aResult = lastName;
+    aResult += firstName;
   }
   else
   {
-    aResult = m_PhoneticFirstName;
-    aResult += m_PhoneticLastName;
+    aResult = firstName;
+    aResult += lastName;
   }
 
   return NS_OK;
 }
--- a/mailnews/addrbook/src/nsAbCardProperty.h
+++ b/mailnews/addrbook/src/nsAbCardProperty.h
@@ -44,96 +44,48 @@
 
 #ifndef nsAbCardProperty_h__
 #define nsAbCardProperty_h__
 
 #include "nsIAbCard.h"  
 #include "nsCOMPtr.h"
 #include "nsStringGlue.h"
 
+#include "nsInterfaceHashtable.h"
+#include "nsIVariant.h"
+
 class nsIStringBundle;
 class mozITXTToHTMLConv;
 struct AppendItem;
 
  /* 
   * Address Book Card Property
   */ 
 
 class nsAbCardProperty: public nsIAbCard
 {
 public: 
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIABCARD
+  NS_DECL_NSIABITEM
 
-	NS_DECL_ISUPPORTS
-	NS_DECL_NSIABCARD
-
-	nsAbCardProperty(void);
-	virtual ~nsAbCardProperty(void);
+  nsAbCardProperty();
+  virtual ~nsAbCardProperty(void);
 
 protected:
-
-	nsString m_PhoneticFirstName;
-	nsString m_PhoneticLastName;
-	nsString m_FirstName;
-	nsString m_LastName;
-	nsString m_DisplayName;
-	nsString m_NickName;
-	nsString m_PrimaryEmail;
-	nsString m_SecondEmail;
-	nsString m_WorkPhone;
-	nsString m_HomePhone;
-	nsString m_FaxNumber;
-	nsString m_PagerNumber;
-	nsString m_CellularNumber;
-  nsString m_WorkPhoneType;
-  nsString m_HomePhoneType;
-  nsString m_FaxNumberType;
-  nsString m_PagerNumberType;
-  nsString m_CellularNumberType;
-	nsString m_HomeAddress;
-	nsString m_HomeAddress2;
-	nsString m_HomeCity;
-	nsString m_HomeState;
-	nsString m_HomeZipCode;
-	nsString m_HomeCountry;
-	nsString m_WorkAddress;
-	nsString m_WorkAddress2;
-	nsString m_WorkCity;
-	nsString m_WorkState;
-	nsString m_WorkZipCode;
-	nsString m_WorkCountry;
-	nsString m_JobTitle;
-	nsString m_Department;
-	nsString m_Company;
-  nsString m_AimScreenName;
-  nsString m_AnniversaryYear;
-  nsString m_AnniversaryMonth;
-  nsString m_AnniversaryDay;
-  nsString m_SpouseName;
-  nsString m_FamilyName;
-  nsString m_DefaultAddress;
-  nsString m_Category;
-	nsString m_WebPage1;
-	nsString m_WebPage2;
-	nsString m_BirthYear;
-	nsString m_BirthMonth;
-	nsString m_BirthDay;
-	nsString m_Custom1;
-	nsString m_Custom2;
-	nsString m_Custom3;
-	nsString m_Custom4;
-	nsString m_Note;
-	PRUint32 m_LastModDate;
-	PRUint32 m_PreferMailFormat;
-	PRUint32 m_PopularityIndex;
-  PRBool   m_AllowRemoteContent;
-
 	PRBool   m_IsMailList;
 	nsCString m_MailListURI;
 
+  // Store most of the properties here
+  nsInterfaceHashtable<nsCStringHashKey, nsIVariant> m_properties;
+
 private:
-  nsresult AppendData(const char *aAttrName, mozITXTToHTMLConv *aConv, nsString &aResult);
   nsresult AppendSection(const AppendItem *aArray, PRInt16 aCount, const nsString& aHeading, nsIStringBundle *aBundle, mozITXTToHTMLConv *aConv, nsString &aResult);
   nsresult AppendLine(const AppendItem &aItem, mozITXTToHTMLConv *aConv, nsString &aResult);
   nsresult AppendLabel(const AppendItem &aItem, nsIStringBundle *aBundle, mozITXTToHTMLConv *aConv, nsString &aResult);
   nsresult AppendCityStateZip(const AppendItem &aItem, nsIStringBundle *aBundle, mozITXTToHTMLConv *aConv, nsString &aResult);
+
+  nsresult ConvertToBase64EncodedXML(nsACString &result);
+  nsresult ConvertToXMLPrintData(nsAString &result);
+  nsresult ConvertToEscapedVCard(nsACString &result);
 };
 
 #endif
--- a/mailnews/addrbook/src/nsAbDirectoryQuery.cpp
+++ b/mailnews/addrbook/src/nsAbDirectoryQuery.cpp
@@ -450,18 +450,17 @@ nsresult nsAbDirectoryQuery::matchCardCo
 
     if (name.Equals ("card:nsIAbCard"))
     {
       *matchFound = (conditionType == nsIAbBooleanConditionTypes::Exists);
       return NS_OK;
     }
 
     nsString value;
-    rv = card->GetCardValue(name.get(), value);
-    NS_ENSURE_SUCCESS(rv, rv);
+    (void)card->GetPropertyAsAString(name.get(), value);
 
     if (value.IsEmpty())
     {
       *matchFound = (conditionType == nsIAbBooleanConditionTypes::DoesNotExist) ?
           PR_TRUE : PR_FALSE;
       return NS_OK;
     }
 
--- a/mailnews/addrbook/src/nsAbLDAPAttributeMap.js
+++ b/mailnews/addrbook/src/nsAbLDAPAttributeMap.js
@@ -183,17 +183,17 @@ nsAbLDAPAttributeMap.prototype = {
 
         attr = attr.toLowerCase();
 
         // find the first attr that exists in this message
         if (msgAttrs.indexOf(attr) != -1) {
           
           try {
             var values = aMessage.getValues(attr, {});
-            aCard.setCardValue(prop, values[0]);
+            aCard.setProperty(prop, values[0]);
 
             cardValueWasSet = true;
             break;
           } catch (ex) {
             // ignore any errors getting message values or setting card values
           }
         }
       }
--- a/mailnews/addrbook/src/nsAbLDAPCard.cpp
+++ b/mailnews/addrbook/src/nsAbLDAPCard.cpp
@@ -47,16 +47,18 @@
 #include "nsIAbLDAPAttributeMap.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsAbBaseCID.h"
 #include "nsAbUtils.h"
 
 #include <stdio.h>
 
+#define kDNColumn "DN"
+
 nsAbLDAPCard::nsAbLDAPCard()
 {
 }
 
 nsAbLDAPCard::~nsAbLDAPCard()
 {
 }
 
@@ -141,65 +143,64 @@ NS_IMETHODIMP nsAbLDAPCard::GetLDAPMessa
 
   // Add card properties
   CharPtrArrayGuard props;
   rv = aAttributeMap->GetAllCardProperties(props.GetSizeAddr(),
     props.GetArrayAddr());
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCAutoString attr;
-  nsString propvalue;
+  nsCString propvalue;
   for (PRUint32 i = 0; i < props.GetSize(); ++i)
   {
     // Skip some attributes that don't map to LDAP.
     //
     // BirthYear : by default this is mapped to 'birthyear',
     // which is not part of mozillaAbPersonAlpha
     //
     // LastModifiedDate : by default this is mapped to 'modifytimestamp',
     // which cannot be modified
     //
     // PreferMailFormat : by default this is mapped to 'mozillaUseHtmlMail',
     // which is a boolean, not plaintext/html/unknown
-    if (!strcmp(props[i], "BirthYear") ||
-        !strcmp(props[i], "LastModifiedDate") ||
-        !strcmp(props[i], "PreferMailFormat"))
+    if (!strcmp(props[i], kBirthYearProperty) ||
+        !strcmp(props[i], kLastModifiedDateProperty) ||
+        !strcmp(props[i], kPreferMailFormatProperty))
       continue;
     
     rv = aAttributeMap->GetFirstAttribute(nsDependentCString(props[i]),
       attr);
     NS_ENSURE_SUCCESS(rv, rv);
     ToLowerCase(attr);
 
     // If the property is not mapped to an attribute, skip it.
     if (attr.IsEmpty())
       continue;
  
-    rv = GetCardValue(props[i], propvalue);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     nsCOMPtr<nsILDAPModification> mod =
       do_CreateInstance("@mozilla.org/network/ldap-modification;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
    
-    if (!propvalue.IsEmpty())
+    rv = GetPropertyAsAUTF8String(props[i], propvalue);
+
+    if (NS_SUCCEEDED(rv) &&!propvalue.IsEmpty())
     {
       // If the new value is not empty, add/update it
       nsCOMPtr<nsILDAPBERValue> value =
         do_CreateInstance("@mozilla.org/network/ldap-ber-value;1", &rv);
       NS_ENSURE_SUCCESS(rv, rv);
 
-      rv = value->SetFromUTF8(NS_ConvertUTF16toUTF8(propvalue));
+      rv = value->SetFromUTF8(propvalue);
       NS_ENSURE_SUCCESS(rv, rv);
  
       rv = mod->SetUpModificationOneValue(aType, attr, value);
       NS_ENSURE_SUCCESS(rv, rv);
     
       printf("LDAP : setting attribute %s (%s) to '%s'\n", attr.get(),
-        props[i], NS_ConvertUTF16toUTF8(propvalue).get());
+        props[i], propvalue.get());
       modArray->AppendElement(mod, PR_FALSE);
       if (m_attributes.IndexOf(attr) != -1)
         m_attributes.AppendCString(attr);
 
     }
     else if ((aType == nsILDAPModification::MOD_REPLACE) &&
                (m_attributes.IndexOf(attr) != -1))
     {
@@ -227,73 +228,70 @@ NS_IMETHODIMP nsAbLDAPCard::BuildRdn(nsI
                                      const PRUint32 aAttrCount,
                                      const char **aAttributes,
                                      nsACString &aRdn)
 {
   NS_ENSURE_ARG_POINTER(aAttributeMap);
   NS_ENSURE_ARG_POINTER(aAttributes);
   
   nsresult rv;
-  nsCAutoString attr;
+  nsCString attr;
   nsCAutoString prop;
-  nsString propvalue;
+  nsCString propvalue;
 
   aRdn.Truncate();
   for (PRUint32 i = 0; i < aAttrCount; ++i)
   {
     attr.Assign(nsDependentCString(aAttributes[i]));
    
     // Lookup the property corresponding to the attribute
     rv = aAttributeMap->GetProperty(attr, prop);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get the property value
-    rv = GetCardValue(prop.get(), propvalue);
-    NS_ENSURE_SUCCESS(rv, rv);
+    rv = GetPropertyAsAUTF8String(prop.get(), propvalue);
 
     // XXX The case where an attribute needed to build the Relative
     // Distinguished Name is not set needs to be handled by the caller,
     // so as to let the user know what is missing.
-    if (propvalue.IsEmpty())
+    if (NS_FAILED(rv) || propvalue.IsEmpty())
     {
       NS_ERROR("nsAbLDAPCard::BuildRdn: a required attribute is not set");
       return NS_ERROR_NOT_INITIALIZED;
     }
   
     aRdn.Append(attr);
     aRdn.AppendLiteral("=");
-    aRdn.Append(NS_ConvertUTF16toUTF8(propvalue));
+    aRdn.Append(propvalue);
     if (i < aAttrCount - 1)
       aRdn.AppendLiteral("+");
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAbLDAPCard::GetDn(nsACString &aDN)
 {
-  aDN = m_dn;
-  return NS_OK;
+  return GetPropertyAsAUTF8String(kDNColumn, aDN);
 }
 
 NS_IMETHODIMP nsAbLDAPCard::SetDn(const nsACString &aDN)
 {
-  m_dn = aDN;
-  return NS_OK;
+  return SetPropertyAsAUTF8String(kDNColumn, aDN);
 }
 
 NS_IMETHODIMP nsAbLDAPCard::SetMetaProperties(nsILDAPMessage *aMessage)
 {
   NS_ENSURE_ARG_POINTER(aMessage);
   
   // Get DN
   nsCAutoString dn;
   nsresult rv = aMessage->GetDn(dn);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  m_dn = dn;
+  SetDn(dn);
 
   // Get the list of set attributes
   CharPtrArrayGuard attrs;
   rv = aMessage->GetAttributes(attrs.GetSizeAddr(), attrs.GetArrayAddr());
   NS_ENSURE_SUCCESS(rv, rv);
  
   nsCAutoString attr;
   m_attributes.Clear();
@@ -316,9 +314,8 @@ NS_IMETHODIMP nsAbLDAPCard::SetMetaPrope
   {
     oclass.Assign(NS_LossyConvertUTF16toASCII(nsDependentString(vals[i])));
     ToLowerCase(oclass);
     m_objectClass.AppendCString(oclass);
   }
 
   return NS_OK;
 }
-
--- a/mailnews/addrbook/src/nsAbLDAPCard.h
+++ b/mailnews/addrbook/src/nsAbLDAPCard.h
@@ -53,14 +53,13 @@ class nsAbLDAPCard : public nsAbCardProp
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIABLDAPCARD
 
   nsAbLDAPCard();
   virtual ~nsAbLDAPCard();
 
 protected:
-  nsCString m_dn;
   nsCStringArray m_attributes;
   nsCStringArray m_objectClass;
 };
 
 #endif
--- a/mailnews/addrbook/src/nsAbLDAPReplicationData.cpp
+++ b/mailnews/addrbook/src/nsAbLDAPReplicationData.cpp
@@ -37,17 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsILDAPMessage.h"
 #include "nsAbLDAPReplicationData.h"
 #include "nsIAbCard.h"
 #include "nsAbBaseCID.h"
 #include "nsAbUtils.h"
-#include "nsIAbMDBCard.h"
 #include "nsAbLDAPReplicationQuery.h"
 #include "nsProxiedService.h"
 #include "nsIRDFService.h"
 #include "nsIRDFResource.h"
 #include "nsILDAPErrors.h"
 #include "nsComponentManagerUtils.h"
 #include "nsXPCOMCIDInternal.h"
 
@@ -274,24 +273,18 @@ nsresult nsAbLDAPProcessReplicationData:
     if (!mReplicationDB || !mDBOpen)
         return NS_ERROR_FAILURE;
 
     nsresult rv = NS_OK;
 
     // Although we would may naturally create an nsIAbLDAPCard here, we don't
     // need to as we are writing this straight to the database, so just create
     // the database version instead.
-    nsCOMPtr<nsIAbMDBCard> dbCard(do_CreateInstance(NS_ABMDBCARD_CONTRACTID,
-                                                    &rv));
-    if (NS_FAILED(rv)) {
-      Abort();
-      return rv;
-    }
-
-    nsCOMPtr<nsIAbCard> newCard(do_QueryInterface(dbCard, &rv));
+    nsCOMPtr<nsIAbCard> newCard(do_CreateInstance(NS_ABMDBCARD_CONTRACTID,
+                                                  &rv));
     if (NS_FAILED(rv)) {
       Abort();
       return rv;
     }
 
     rv = mAttrMap->SetCardPropertiesFromLDAPMessage(aMessage, newCard);
     if (NS_FAILED(rv))
     {
@@ -307,24 +300,17 @@ nsresult nsAbLDAPProcessReplicationData:
         return rv;
     }
 
     // now set the attribute for the DN of the entry in the card in the DB
     nsCAutoString authDN;
     rv = aMessage->GetDn(authDN);
     if(NS_SUCCEEDED(rv) && !authDN.IsEmpty())
     {
-        dbCard->SetAbDatabase(mReplicationDB);
-        dbCard->SetStringAttribute("_DN", NS_ConvertUTF8toUTF16(authDN).get());
-    }
-
-    newCard = do_QueryInterface(dbCard, &rv);
-    if(NS_FAILED(rv)) {
-        Abort();
-        return rv;
+        newCard->SetPropertyAsAUTF8String("_DN", authDN);
     }
 
     rv = mReplicationDB->EditCard(newCard, PR_FALSE, nsnull);
     if(NS_FAILED(rv)) {
         Abort();
         return rv;
     }
     
--- a/mailnews/addrbook/src/nsAbMDBCard.cpp
+++ b/mailnews/addrbook/src/nsAbMDBCard.cpp
@@ -34,119 +34,52 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAbMDBCard.h"
 
 nsAbMDBCard::nsAbMDBCard(void)
-  : m_key(0),
-    m_dbTableID(0),
-    m_dbRowID(0)
 {
 }
 
 nsAbMDBCard::~nsAbMDBCard(void)
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsAbMDBCard, nsAbCardProperty, nsIAbMDBCard)
-
-NS_IMETHODIMP nsAbMDBCard::GetDbTableID(PRUint32 *aDbTableID)
-{
-  *aDbTableID = m_dbTableID;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbMDBCard::SetDbTableID(PRUint32 aDbTableID)
-{
-  m_dbTableID = aDbTableID;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbMDBCard::GetDbRowID(PRUint32 *aDbRowID)
-{
-  *aDbRowID = m_dbRowID;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbMDBCard::SetDbRowID(PRUint32 aDbRowID)
-{
-  m_dbRowID = aDbRowID;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbMDBCard::GetKey(PRUint32 *aKey)
-{
-  *aKey = m_key;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbMDBCard::SetKey(PRUint32 key)
-{
-  m_key = key;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbMDBCard::SetAbDatabase(nsIAddrDatabase* database)
-{
-  mCardDatabase = database;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsAbMDBCard::SetStringAttribute(const char *name, const PRUnichar *value)
-{
-  NS_ASSERTION(mCardDatabase, "no db");
-  if (!mCardDatabase)
-    return NS_ERROR_UNEXPECTED;
-
-  return mCardDatabase->SetCardValue(this, name, value, PR_TRUE /* notify */);
-}  
-
-NS_IMETHODIMP nsAbMDBCard::GetStringAttribute(const char *name, PRUnichar **value)
-{
-  NS_ASSERTION(mCardDatabase, "no db");
-  if (!mCardDatabase)
-    return NS_ERROR_UNEXPECTED;
-
-  return mCardDatabase->GetCardValue(this, name, value);
-}
+NS_IMPL_ISUPPORTS_INHERITED0(nsAbMDBCard, nsAbCardProperty)
 
 NS_IMETHODIMP nsAbMDBCard::Equals(nsIAbCard *card, PRBool *result)
 {
-  nsresult rv;
-
   if (this == card) {
     *result = PR_TRUE;
     return NS_OK;
   }
 
-  // the reason we need this card at all is that multiple nsIAbCards
-  // can exist for a given mdbcard
-  nsCOMPtr <nsIAbMDBCard> mdbcard = do_QueryInterface(card, &rv);
-  if (NS_FAILED(rv) || !mdbcard) {
-    // XXX using ldap can get us here, we need to fix how the listeners work
+  // If we have the same directory, we will equal the other card merely given
+  // the row IDs. If not, we are never equal. But we are dumb in that we don't
+  // know who our directory is, which may change in the future. For now,
+  // however, the only known users of this method are for locating us in a list
+  // of cards, most commonly mailing lists; a warning on the IDL has also
+  // notified consumers that this method is not generally safe to use. In this
+  // respect, it is safe to assume that the directory portion is satisified when
+  // making this call.
+  // However, if we make the wrong assumption, one of two things will happen.
+  // If the other directory is a local address book, we could return a spurious
+  // true result. If not, then DbRowID should be unset and we can definitively
+  // return false.
+
+  PRUint32 row;
+  nsresult rv = card->GetPropertyAsUint32("DbRowID", &row);
+  if (NS_FAILED(rv))
+  {
     *result = PR_FALSE;
     return NS_OK;
   }
 
-  // XXX todo
-  // optimize this code, key might be enough
-  PRUint32 dbRowID;
-  rv = mdbcard->GetDbRowID(&dbRowID);
-  NS_ENSURE_SUCCESS(rv,rv);
+  PRUint32 ourRow;
+  rv = GetPropertyAsUint32("DbRowID", &ourRow);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  PRUint32 dbTableID;
-  rv = mdbcard->GetDbTableID(&dbTableID);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  PRUint32 key;
-  rv = mdbcard->GetKey(&key);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  if (dbRowID == m_dbRowID && dbTableID == m_dbTableID && key == m_key)
-    *result = PR_TRUE;
-  else
-    *result = PR_FALSE;
+  *result = (row == ourRow);
   return NS_OK;
 }
-
--- a/mailnews/addrbook/src/nsAbMDBCard.h
+++ b/mailnews/addrbook/src/nsAbMDBCard.h
@@ -34,34 +34,23 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsAbMDBCard_h__
 #define nsAbMDBCard_h__
 
-#include "nsIAbMDBCard.h"
 #include "nsAbCardProperty.h"
 #include "nsCOMPtr.h"
-#include "nsIAddrDatabase.h"
 
-class nsAbMDBCard: public nsIAbMDBCard,
-                   public nsAbCardProperty
+class nsAbMDBCard: public nsAbCardProperty
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIABMDBCARD
 
   nsAbMDBCard(void);
   virtual ~nsAbMDBCard(void);
 
   NS_IMETHOD Equals(nsIAbCard *card, PRBool *result);
-
-protected:
-  PRUint32 m_key;
-  PRUint32 m_dbTableID;
-  PRUint32 m_dbRowID;
-
-  nsCOMPtr<nsIAddrDatabase> mCardDatabase;
 };
 
 #endif
--- a/mailnews/addrbook/src/nsAbMDBDirProperty.cpp
+++ b/mailnews/addrbook/src/nsAbMDBDirProperty.cpp
@@ -43,17 +43,16 @@
 #include "nsIServiceManager.h"
 #include "nsRDFCID.h"
 #include "nsStringGlue.h"
 #include "nsCOMPtr.h"
 #include "nsAbBaseCID.h"
 #include "nsAddrDatabase.h"
 #include "nsIAbCard.h"
 #include "nsIAbListener.h"
-#include "nsIAbMDBCard.h"
 #include "nsArrayUtils.h"
 #include "mdb.h"
 #include "nsComponentManagerUtils.h"
 
 nsAbMDBDirProperty::nsAbMDBDirProperty(void)
 {
   m_dbRowID = 0;
 }
--- a/mailnews/addrbook/src/nsAbMDBDirectory.cpp
+++ b/mailnews/addrbook/src/nsAbMDBDirectory.cpp
@@ -39,17 +39,16 @@
 
 #include "nsAbMDBDirectory.h" 
 #include "nsIRDFService.h"
 #include "nsRDFCID.h"
 #include "nsStringGlue.h"
 #include "nsCOMPtr.h"
 #include "nsAbBaseCID.h"
 #include "nsAddrDatabase.h"
-#include "nsIAbMDBCard.h"
 #include "nsIAbListener.h"
 #include "nsIAbManager.h"
 #include "nsIURL.h"
 #include "nsNetCID.h"
 #include "nsAbDirectoryQuery.h"
 #include "nsIAbDirectoryQueryProxy.h"
 #include "nsAbQueryStringToExpression.h"
 #include "nsIMutableArray.h"
@@ -499,54 +498,51 @@ NS_IMETHODIMP nsAbMDBDirectory::DeleteCa
     PRUint32 i;
     rv = aCards->GetLength(&cardCount);
     NS_ENSURE_SUCCESS(rv, rv);
     for (i = 0; i < cardCount; i++)
     {
       nsCOMPtr<nsIAbCard> card(do_QueryElementAt(aCards, i, &rv));
       NS_ENSURE_SUCCESS(rv, rv);
 
-      nsCOMPtr<nsIAbMDBCard> dbcard(do_QueryInterface(card, &rv));
-      NS_ENSURE_SUCCESS(rv, rv);
-
       if (card)
       {
+        PRUint32 rowID;
+        rv = card->GetPropertyAsUint32("DbRowID", &rowID);
+        NS_ENSURE_SUCCESS(rv, rv);
+
         if (m_IsMailList)
         {
           mDatabase->DeleteCardFromMailList(this, card, PR_TRUE);
 
           PRUint32 cardTotal = 0;
           PRInt32 i;
           if (m_AddressList)
             rv = m_AddressList->GetLength(&cardTotal);
           for (i = cardTotal - 1; i >= 0; i--)
           {            
-            nsCOMPtr<nsIAbMDBCard> dbarrayCard(do_QueryElementAt(m_AddressList, i, &rv));
-            if (dbarrayCard)
+            nsCOMPtr<nsIAbCard> arrayCard(do_QueryElementAt(m_AddressList, i, &rv));
+            if (arrayCard)
             {
-              PRUint32 tableID, rowID, cardTableID, cardRowID; 
-              dbarrayCard->GetDbTableID(&tableID);
-              dbarrayCard->GetDbRowID(&rowID);
-              dbcard->GetDbTableID(&cardTableID);
-              dbcard->GetDbRowID(&cardRowID);
-              if (tableID == cardTableID && rowID == cardRowID)
+              // No card can have a row ID of 0
+              PRUint32 arrayRowID = 0;
+              arrayCard->GetPropertyAsUint32("DbRowID", &arrayRowID);
+              if (rowID == arrayRowID)
                 m_AddressList->RemoveElementAt(i);
             }
           }
         }
         else
         {
           mDatabase->DeleteCard(card, PR_TRUE, this);
           PRBool bIsMailList = PR_FALSE;
           card->GetIsMailList(&bIsMailList);
           if (bIsMailList)
           {
             //to do, get mailing list dir side uri and notify rdf to remove it
-            PRUint32 rowID;
-            dbcard->GetDbRowID(&rowID);
             nsCAutoString listUri(mURI);
             listUri.AppendLiteral("/MailList");
             listUri.AppendInt(rowID);
             if (!listUri.IsEmpty())
             {
               nsresult rv = NS_OK;
               nsCOMPtr<nsIRDFService> rdfService = 
                        do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
@@ -692,42 +688,25 @@ NS_IMETHODIMP nsAbMDBDirectory::AddCard(
 
   nsresult rv = NS_OK;
   if (!mDatabase)
     rv = GetAbDatabase();
 
   if (NS_FAILED(rv) || !mDatabase)
     return NS_ERROR_FAILURE;
 
-  nsCOMPtr<nsIAbCard> newCard;
-  nsCOMPtr<nsIAbMDBCard> dbcard;
-
-  dbcard = do_QueryInterface(card, &rv);
-  if (NS_FAILED(rv) || !dbcard) {
-    dbcard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
+  if (m_IsMailList)
+    rv = mDatabase->CreateNewListCardAndAddToDB(this, m_dbRowID, card, PR_TRUE /* notify */);
+  else
+    rv = mDatabase->CreateNewCardAndAddToDB(card, PR_TRUE, this);
   NS_ENSURE_SUCCESS(rv, rv);
 
-    newCard = do_QueryInterface(dbcard, &rv);
-    NS_ENSURE_SUCCESS(rv,rv);
-  
-    rv = newCard->Copy(card);
-  NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    newCard = card;
-  }
-
-  dbcard->SetAbDatabase (mDatabase);
-  if (m_IsMailList)
-    mDatabase->CreateNewListCardAndAddToDB(this, m_dbRowID, newCard, PR_TRUE /* notify */);
-  else
-    mDatabase->CreateNewCardAndAddToDB(newCard, PR_TRUE, this);
   mDatabase->Commit(nsAddrDBCommitType::kLargeCommit);
 
-  NS_IF_ADDREF(*addedCard = newCard);
+  NS_IF_ADDREF(*addedCard = card);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAbMDBDirectory::ModifyCard(nsIAbCard *aModifiedCard)
 {
   NS_ENSURE_ARG_POINTER(aModifiedCard);
 
   nsresult rv;
@@ -753,36 +732,28 @@ NS_IMETHODIMP nsAbMDBDirectory::DropCard
 
   if (!mDatabase)
     rv = GetAbDatabase();
 
   if (NS_FAILED(rv) || !mDatabase)
     return NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIAbCard> newCard;
-  nsCOMPtr<nsIAbMDBCard> dbcard;
 
   if (needToCopyCard) {
-    dbcard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+    newCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
 
-    newCard = do_QueryInterface(dbcard, &rv);
-    NS_ENSURE_SUCCESS(rv,rv);
-  
     rv = newCard->Copy(aCard);
-  NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
-    dbcard = do_QueryInterface(aCard, &rv);
-    NS_ENSURE_SUCCESS(rv,rv);
     newCard = aCard;
   }  
 
-  dbcard->SetAbDatabase(mDatabase);
-
   if (m_IsMailList) {
     if (needToCopyCard) {
       nsCOMPtr <nsIMdbRow> cardRow;
       // if card doesn't exist in db, add the card to the directory that 
       // contains the mailing list.
       mDatabase->FindRowByCard(newCard, getter_AddRefs(cardRow));
       if (!cardRow)
         mDatabase->CreateNewCardAndAddToDB(newCard, PR_TRUE /* notify */, this);
@@ -1086,13 +1057,13 @@ NS_IMETHODIMP nsAbMDBDirectory::CardForE
   if (!*aAbCard) 
   {
     // fix for bug #187239
     // didn't find it as the primary email?  try again, with k2ndEmailColumn ("Additional Email")
     // 
     // TODO bug #198731
     // unlike the kPriEmailColumn, we don't have kLower2ndEmailColumn
     // so we will still suffer from bug #196777 for "additional emails"
-    mDatabase->GetCardFromAttribute(this, k2ndEmailColumn, aEmailAddress, PR_TRUE /* caseInsensitive, see bug #191798 */, aAbCard);
+    mDatabase->GetCardFromAttribute(this, k2ndEmailProperty, aEmailAddress, PR_TRUE /* caseInsensitive, see bug #191798 */, aAbCard);
   }
 
   return NS_OK;
 }
--- a/mailnews/addrbook/src/nsAbManager.cpp
+++ b/mailnews/addrbook/src/nsAbManager.cpp
@@ -65,17 +65,17 @@
 #include "nsICommandLine.h"
 #include "nsILocalFile.h"
 #include "nsIMutableArray.h"
 #include "nsArrayUtils.h"
 #include "nsDirectoryServiceUtils.h"
 
 struct ExportAttributesTableStruct
 {
-  const char* abColName;
+  const char* abPropertyName;
   PRUint32 plainTextStringID;
 };
 
 // our schema is not fixed yet, but we still want some sort of objectclass
 // for now, use obsolete in the class name, hinting that this will change
 // see bugs bug #116692 and #118454
 #define MOZ_AB_OBJECTCLASS "mozillaAbPersonAlpha"
 
@@ -89,67 +89,65 @@ struct ExportAttributesTableStruct
 // here's how we're coming up with the ldapPropertyName values
 // if they are specified in RFC 2798, use them
 // else use the 4.x LDIF attribute names (for example, "xmozillanickname"
 // as we want to allow export from mozilla back to 4.x, and other apps
 // are probably out there that can handle 4.x LDIF)
 // else use the MOZ_AB_LDIF_PREFIX prefix, see nsIAddrDatabase.idl
 
 const ExportAttributesTableStruct EXPORT_ATTRIBUTES_TABLE[] = {
-  {kFirstNameColumn, 2100},
-  {kLastNameColumn, 2101},
-  {kDisplayNameColumn, 2102},
-  {kNicknameColumn, 2103},
-  {kPriEmailColumn, 2104},
-  {k2ndEmailColumn, 2105},
-  {kAimScreenNameColumn},
-  {kPreferMailFormatColumn},
-  {kLastModifiedDateColumn},
-  {kWorkPhoneColumn, 2106},
-  {kWorkPhoneTypeColumn},
-  {kHomePhoneColumn, 2107},
-  {kHomePhoneTypeColumn},
-  {kFaxColumn, 2108},
-  {kFaxTypeColumn},
-  {kPagerColumn, 2109},
-  {kPagerTypeColumn},
-  {kCellularColumn, 2110},
-  {kCellularTypeColumn},
-  {kHomeAddressColumn, 2111},
-  {kHomeAddress2Column, 2112},
-  {kHomeCityColumn, 2113},
-  {kHomeStateColumn, 2114},
-  {kHomeZipCodeColumn, 2115},
-  {kHomeCountryColumn, 2116},
-  {kWorkAddressColumn, 2117},
-  {kWorkAddress2Column, 2118},
-  {kWorkCityColumn, 2119},
-  {kWorkStateColumn, 2120},
-  {kWorkZipCodeColumn, 2121},
-  {kWorkCountryColumn, 2122},
-  {kJobTitleColumn, 2123},
-  {kDepartmentColumn, 2124},
-  {kCompanyColumn, 2125},
-  {kWebPage1Column, 2126},
-  {kWebPage2Column, 2127},
-  {kBirthYearColumn, 2128}, // unused for now
-  {kBirthMonthColumn, 2129}, // unused for now
-  {kBirthDayColumn, 2130}, // unused for now
-  {kCustom1Column, 2131},
-  {kCustom2Column, 2132},
-  {kCustom3Column, 2133},
-  {kCustom4Column, 2134},
-  {kNotesColumn, 2135},
-  {kAnniversaryYearColumn},
-  {kAnniversaryMonthColumn},
-  {kAnniversaryDayColumn},
-  {kSpouseNameColumn},
-  {kFamilyNameColumn},
-  {kDefaultAddressColumn},
-  {kCategoryColumn},
+  {kFirstNameProperty, 2100},
+  {kLastNameProperty, 2101},
+  {kDisplayNameProperty, 2102},
+  {kNicknameProperty, 2103},
+  {kPriEmailProperty, 2104},
+  {k2ndEmailProperty, 2105},
+  {kScreenNameProperty},
+  {kPreferMailFormatProperty},
+  {kLastModifiedDateProperty},
+  {kWorkPhoneProperty, 2106},
+  {kWorkPhoneTypeProperty},
+  {kHomePhoneProperty, 2107},
+  {kHomePhoneTypeProperty},
+  {kFaxProperty, 2108},
+  {kFaxTypeProperty},
+  {kPagerProperty, 2109},
+  {kPagerTypeProperty},
+  {kCellularProperty, 2110},
+  {kCellularTypeProperty},
+  {kHomeAddressProperty, 2111},
+  {kHomeAddress2Property, 2112},
+  {kHomeCityProperty, 2113},
+  {kHomeStateProperty, 2114},
+  {kHomeZipCodeProperty, 2115},
+  {kHomeCountryProperty, 2116},
+  {kWorkAddressProperty, 2117},
+  {kWorkAddress2Property, 2118},
+  {kWorkCityProperty, 2119},
+  {kWorkStateProperty, 2120},
+  {kWorkZipCodeProperty, 2121},
+  {kWorkCountryProperty, 2122},
+  {kJobTitleProperty, 2123},
+  {kDepartmentProperty, 2124},
+  {kCompanyProperty, 2125},
+  {kWorkWebPageProperty, 2126},
+  {kHomeWebPageProperty, 2127},
+  {kBirthYearProperty, 2128}, // unused for now
+  {kBirthMonthProperty, 2129}, // unused for now
+  {kBirthDayProperty, 2130}, // unused for now
+  {kCustom1Property, 2131},
+  {kCustom2Property, 2132},
+  {kCustom3Property, 2133},
+  {kCustom4Property, 2134},
+  {kNotesProperty, 2135},
+  {kAnniversaryYearProperty},
+  {kAnniversaryMonthProperty},
+  {kAnniversaryDayProperty},
+  {kSpouseNameProperty},
+  {kFamilyNameProperty},
 };
 
 //
 // nsAbManager
 //
 nsAbManager::nsAbManager()
 {
 }
@@ -618,19 +616,19 @@ nsAbManager::ExportDirectoryToDelimitedT
           // use LDIF for that.
         }
         else {
           nsString value;
           nsCString valueCStr;
 
           for (i = 0; i < NS_ARRAY_LENGTH(EXPORT_ATTRIBUTES_TABLE); i++) {
             if (EXPORT_ATTRIBUTES_TABLE[i].plainTextStringID != 0) {
-              rv = card->GetCardValue(EXPORT_ATTRIBUTES_TABLE[i].abColName,
-                                      value);
-              NS_ENSURE_SUCCESS(rv,rv);
+              rv = card->GetPropertyAsAString(EXPORT_ATTRIBUTES_TABLE[i].abPropertyName, value);
+              if (NS_FAILED(rv))
+                value.Truncate();
 
               // If a string contains at least one comma, tab or double quote then
               // we need to quote the entire string. Also if double quote is part
               // of the string we need to quote the double quote(s) as well.
               nsAutoString newValue(value);
               PRBool needsQuotes = PR_FALSE;
               if(newValue.FindChar('"') != -1)
               {
@@ -786,25 +784,25 @@ nsAbManager::ExportDirectoryToLDIF(nsIAb
           if (length != writeCount)
             return NS_ERROR_FAILURE;
 
           valueCStr.Truncate();
 
           nsCAutoString ldapAttribute;
 
           for (i = 0; i < NS_ARRAY_LENGTH(EXPORT_ATTRIBUTES_TABLE); i++) {
-            if (NS_SUCCEEDED(attrMap->GetFirstAttribute(nsDependentCString(EXPORT_ATTRIBUTES_TABLE[i].abColName),
+            if (NS_SUCCEEDED(attrMap->GetFirstAttribute(nsDependentCString(EXPORT_ATTRIBUTES_TABLE[i].abPropertyName),
                                                         ldapAttribute)) &&
                 !ldapAttribute.IsEmpty()) {
 
-              rv = card->GetCardValue(EXPORT_ATTRIBUTES_TABLE[i].abColName,
-                                      value);
-              NS_ENSURE_SUCCESS(rv,rv);
+              rv = card->GetPropertyAsAString(EXPORT_ATTRIBUTES_TABLE[i].abPropertyName, value);
+              if (NS_FAILED(rv))
+                value.Truncate();
 
-              if (!PL_strcmp(EXPORT_ATTRIBUTES_TABLE[i].abColName, kPreferMailFormatColumn)) {
+              if (!PL_strcmp(EXPORT_ATTRIBUTES_TABLE[i].abPropertyName, kPreferMailFormatProperty)) {
                 if (value.Equals(NS_LITERAL_STRING("html").get()))
                   value.AssignLiteral("true");
                 else if (value.Equals(NS_LITERAL_STRING("plaintext").get()))
                   value.AssignLiteral("false");
                 else
                   value.Truncate(); // unknown.
               }
 
@@ -857,50 +855,46 @@ nsresult nsAbManager::AppendLDIFForMailL
 
   rv = AppendDNForCard("dn", aCard, aAttrMap, aResult);
   NS_ENSURE_SUCCESS(rv,rv);
 
   aResult += MSG_LINEBREAK \
              "objectclass: top" MSG_LINEBREAK \
              "objectclass: groupOfNames" MSG_LINEBREAK;
 
-  rv = aCard->GetCardValue(kDisplayNameColumn, attrValue);
+  rv = aCard->GetDisplayName(attrValue);
   NS_ENSURE_SUCCESS(rv,rv);
 
   nsCAutoString ldapAttributeName;
 
-  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kDisplayNameColumn),
+  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kDisplayNameProperty),
                                   ldapAttributeName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = AppendProperty(ldapAttributeName.get(), attrValue.get(), aResult);
   NS_ENSURE_SUCCESS(rv,rv);
   aResult += MSG_LINEBREAK;
 
-  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kNicknameColumn),
+  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kNicknameProperty),
                                   ldapAttributeName);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aCard->GetCardValue(kNicknameColumn, attrValue);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  if (!attrValue.IsEmpty()) {
+  rv = aCard->GetPropertyAsAString(kNicknameProperty, attrValue);
+  if (NS_SUCCEEDED(rv) && !attrValue.IsEmpty()) {
     rv = AppendProperty(ldapAttributeName.get(), attrValue.get(), aResult);
     NS_ENSURE_SUCCESS(rv,rv);
     aResult += MSG_LINEBREAK;
   }
 
-  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kNotesColumn),
+  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kNotesProperty),
                                   ldapAttributeName);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aCard->GetCardValue(kNotesColumn, attrValue);
-  NS_ENSURE_SUCCESS(rv,rv);
-
-  if (!attrValue.IsEmpty()) {
+  rv = aCard->GetPropertyAsAString(kNotesProperty, attrValue);
+  if (NS_SUCCEEDED(rv) && !attrValue.IsEmpty()) {
     rv = AppendProperty(ldapAttributeName.get(), attrValue.get(), aResult);
     NS_ENSURE_SUCCESS(rv,rv);
     aResult += MSG_LINEBREAK;
   }
 
   nsCOMPtr<nsIRDFService> rdfService = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
   NS_ENSURE_SUCCESS(rv,rv);
 
@@ -939,38 +933,38 @@ nsresult nsAbManager::AppendLDIFForMailL
 }
 
 nsresult nsAbManager::AppendDNForCard(const char *aProperty, nsIAbCard *aCard, nsIAbLDAPAttributeMap *aAttrMap, nsACString &aResult)
 {
   nsString email;
   nsString displayName;
   nsCAutoString ldapAttributeName;
 
-  nsresult rv = aCard->GetCardValue(kPriEmailColumn, email);
+  nsresult rv = aCard->GetPrimaryEmail(email);
   NS_ENSURE_SUCCESS(rv,rv);
 
-  rv = aCard->GetCardValue(kDisplayNameColumn, displayName);
+  rv = aCard->GetDisplayName(displayName);
   NS_ENSURE_SUCCESS(rv,rv);
 
   nsString cnStr;
 
-  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kDisplayNameColumn),
+  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kDisplayNameProperty),
                                    ldapAttributeName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!displayName.IsEmpty()) {
     cnStr += NS_ConvertUTF8toUTF16(ldapAttributeName).get();
     cnStr.AppendLiteral("=");
     cnStr.Append(displayName);
     if (!email.IsEmpty()) {
       cnStr.AppendLiteral(",");
     }
   }
 
-  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kPriEmailColumn),
+  rv = aAttrMap->GetFirstAttribute(NS_LITERAL_CSTRING(kPriEmailProperty),
                                    ldapAttributeName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!email.IsEmpty()) {
     cnStr += NS_ConvertUTF8toUTF16(ldapAttributeName).get();
     cnStr.AppendLiteral("=");
     cnStr.Append(email);
   }
@@ -1044,77 +1038,77 @@ char *getCString(VObject *vObj)
         return fakeCString(vObjectUStringZValue(vObj));
     if (VALUE_TYPE(vObj) == VCVT_STRINGZ)
         return PL_strdup(vObjectStringZValue(vObj));
     return NULL;
 }
 
 static void convertNameValue(VObject *vObj, nsIAbCard *aCard)
 {
-  const char *cardColName = NULL;
+  const char *cardPropName = NULL;
 
   // if the vCard property is not a root property then we need to determine its exact property.
   // a good example of this is VCTelephoneProp, this prop has four objects underneath it:
   // fax, work and home and cellular.
   if (PL_strcasecmp(VCCityProp, vObjectName(vObj)) == 0)
-      cardColName = kWorkCityColumn;
+      cardPropName = kWorkCityProperty;
   else if (PL_strcasecmp(VCTelephoneProp, vObjectName(vObj)) == 0)
   {
       if (isAPropertyOf(vObj, VCFaxProp))
-          cardColName = kFaxColumn;
+          cardPropName = kFaxProperty;
       else if (isAPropertyOf(vObj, VCWorkProp))
-          cardColName = kWorkPhoneColumn;
+          cardPropName = kWorkPhoneProperty;
       else if (isAPropertyOf(vObj, VCHomeProp))
-          cardColName = kHomePhoneColumn;
+          cardPropName = kHomePhoneProperty;
       else if (isAPropertyOf(vObj, VCCellularProp))
-          cardColName = kCellularColumn;
+          cardPropName = kCellularProperty;
       else if (isAPropertyOf(vObj, VCPagerProp))
-          cardColName = kPagerColumn;
+          cardPropName = kPagerProperty;
       else
           return;
   }
   else if (PL_strcasecmp(VCEmailAddressProp, vObjectName(vObj)) == 0)
-      cardColName = kPriEmailColumn;
+      cardPropName = kPriEmailProperty;
   else if (PL_strcasecmp(VCFamilyNameProp, vObjectName(vObj)) == 0)
-      cardColName = kLastNameColumn;
+      cardPropName = kLastNameProperty;
   else if (PL_strcasecmp(VCFullNameProp, vObjectName(vObj)) == 0)
-      cardColName = kDisplayNameColumn;
+      cardPropName = kDisplayNameProperty;
   else if (PL_strcasecmp(VCGivenNameProp, vObjectName(vObj)) == 0)
-      cardColName = kFirstNameColumn;
+      cardPropName = kFirstNameProperty;
   else if (PL_strcasecmp(VCOrgNameProp, vObjectName(vObj)) == 0)
-      cardColName = kCompanyColumn;
+      cardPropName = kCompanyProperty;
   else if (PL_strcasecmp(VCOrgUnitProp, vObjectName(vObj)) == 0)
-      cardColName = kDepartmentColumn;
+      cardPropName = kDepartmentProperty;
   else if (PL_strcasecmp(VCPostalCodeProp, vObjectName(vObj)) == 0)
-      cardColName = kWorkZipCodeColumn;
+      cardPropName = kWorkZipCodeProperty;
   else if (PL_strcasecmp(VCRegionProp, vObjectName(vObj)) == 0)
-      cardColName = kWorkStateColumn;
+      cardPropName = kWorkStateProperty;
   else if (PL_strcasecmp(VCStreetAddressProp, vObjectName(vObj)) == 0)
-      cardColName = kWorkAddressColumn;
+      cardPropName = kWorkAddressProperty;
   else if (PL_strcasecmp(VCPostalBoxProp, vObjectName(vObj)) == 0)
-      cardColName = kWorkAddress2Column;
+      cardPropName = kWorkAddress2Property;
   else if (PL_strcasecmp(VCCountryNameProp, vObjectName(vObj)) == 0)
-      cardColName = kWorkCountryColumn;
+      cardPropName = kWorkCountryProperty;
   else if (PL_strcasecmp(VCTitleProp, vObjectName(vObj)) == 0)
-      cardColName = kJobTitleColumn;
+      cardPropName = kJobTitleProperty;
   else if (PL_strcasecmp(VCUseHTML, vObjectName(vObj)) == 0)
-      cardColName = kPreferMailFormatColumn;
+      cardPropName = kPreferMailFormatProperty;
   else if (PL_strcasecmp(VCNoteProp, vObjectName(vObj)) == 0)
-      cardColName = kNotesColumn;
+      cardPropName = kNotesProperty;
   else if (PL_strcasecmp(VCURLProp, vObjectName(vObj)) == 0)
-      cardColName = kWebPage1Column;
+      cardPropName = kWorkWebPageProperty;
   else
       return;
 
   if (!VALUE_TYPE(vObj))
       return;
 
-  char *cardColValue = getCString(vObj);
-  aCard->SetCardValue(cardColName, NS_ConvertUTF8toUTF16(cardColValue));
-  PR_FREEIF(cardColValue);
+  char *cardPropValue = getCString(vObj);
+  aCard->SetPropertyAsAUTF8String(cardPropName, nsDependentCString(cardPropValue));
+  PR_FREEIF(cardPropValue);
   return;
 }
 
 static void convertFromVObject(VObject *vObj, nsIAbCard *aCard)
 {
     if (vObj)
     {
         VObjectIterator t;
--- a/mailnews/addrbook/src/nsAbOSXCard.mm
+++ b/mailnews/addrbook/src/nsAbOSXCard.mm
@@ -69,84 +69,85 @@ GetPropertType(ABRecord *aCard, NSString
     propertyType = [ABPerson typeOfProperty:aProperty];
   else if ([aCard isKindOfClass:[ABGroup class]])
     propertyType = [ABGroup typeOfProperty:aProperty];
   return propertyType;
 }
 #endif
 
 static void
-SetStringProperty(nsAbOSXCard *aCard, nsString &aValue, nsString &aMember,
-                  const char *aMemberName, PRBool aNotify,
-                  nsIAbManager *aAbManager)
+SetStringProperty(nsAbOSXCard *aCard, nsString &aValue, const char *aMemberName,
+                  PRBool aNotify, nsIAbManager *aAbManager)
 {
+  nsString oldValue;
+  nsresult rv = aCard->GetPropertyAsAString(aMemberName, oldValue);
+  if (NS_FAILED(rv))
+    oldValue.Truncate();
+
   if (!aNotify) {
-    aMember = aValue;
+    aCard->SetPropertyAsAString(aMemberName, aValue);
   }
-  else if (!aMember.Equals(aValue)) {
-    nsString oldValue(aMember);
-    aMember = aValue;
+  else if (!oldValue.Equals(aValue)) {
+    aCard->SetPropertyAsAString(aMemberName, aValue);
     
     nsISupports *supports = NS_ISUPPORTS_CAST(nsRDFResource*, aCard);
     aAbManager->NotifyItemPropertyChanged(supports, aMemberName,
-                                        oldValue.get(), aMember.get());
+                                          oldValue.get(), aValue.get());
   }
 }
 
 static void
-SetStringProperty(nsAbOSXCard *aCard, NSString *aValue, nsString &aMember,
-                  const char *aMemberName, PRBool aNotify,
-                  nsIAbManager *aAbManager)
+SetStringProperty(nsAbOSXCard *aCard, NSString *aValue, const char *aMemberName,
+                  PRBool aNotify, nsIAbManager *aAbManager)
 {
   nsAutoString value;
   if (aValue)
     AppendToString(aValue, value);
 
-  SetStringProperty(aCard, value, aMember, aMemberName, aNotify, aAbManager);
+  SetStringProperty(aCard, value, aMemberName, aNotify, aAbManager);
 }
 
 static void
 MapStringProperty(nsAbOSXCard *aCard, ABRecord *aOSXCard, NSString *aProperty,
-                  nsString &aMember, const char *aMemberName, PRBool aNotify,
+                  const char *aMemberName, PRBool aNotify,
                   nsIAbManager *aAbManager)
 {
   NS_ASSERTION(aProperty, "This is bad! You asked for an unresolved symbol.");
   NS_ASSERTION(GetPropertType(aOSXCard, aProperty) == kABStringProperty,
                "Wrong type!");
   
-  SetStringProperty(aCard, [aOSXCard valueForProperty:aProperty], aMember,
-                    aMemberName, aNotify, aAbManager);
+  SetStringProperty(aCard, [aOSXCard valueForProperty:aProperty], aMemberName,
+                    aNotify, aAbManager);
 }
 
 static ABMutableMultiValue*
 GetMultiValue(ABRecord *aCard, NSString *aProperty)
 {
   NS_ASSERTION(aProperty, "This is bad! You asked for an unresolved symbol.");
   NS_ASSERTION(GetPropertType(aCard, aProperty) & kABMultiValueMask,
                "Wrong type!");
   
   return [aCard valueForProperty:aProperty];
 }
 
 static void
-MapDate(nsAbOSXCard *aCard, NSDate *aDate, nsString &aYear,
-        const char *aYearName, nsString &aMonth, const char *aMonthName,
-        nsString &aDay, const char *aDayName, PRBool aNotify,
+MapDate(nsAbOSXCard *aCard, NSDate *aDate, const char *aYearPropName,
+        const char *aMonthPropName, const char *aDayPropName, PRBool aNotify,
         nsIAbManager *aAbManager)
 {
   // XXX Should we pass a format and timezone?
   NSCalendarDate *date = [aDate dateWithCalendarFormat:nil timeZone:nil];
   
   nsAutoString value;
   value.AppendInt([date yearOfCommonEra]);
-  SetStringProperty(aCard, value, aYear, aYearName, aNotify, aAbManager);
+  SetStringProperty(aCard, value, aYearPropName, aNotify, aAbManager);
   value.AppendInt([date monthOfYear]);
-  SetStringProperty(aCard, value, aMonth, aMonthName, aNotify, aAbManager);
+  SetStringProperty(aCard, value, aMonthPropName, aNotify, aAbManager);
   value.AppendInt([date dayOfWeek]);
-  SetStringProperty(aCard, value, aDay, aDayName, aNotify, aAbManager);
+  SetStringProperty(aCard, value, aDayPropName, aNotify, aAbManager);
 }
 
 static PRBool
 MapMultiValue(nsAbOSXCard *aCard, ABRecord *aOSXCard,
               const nsAbOSXPropertyMap &aMap, PRBool aNotify,
               nsIAbManager *aAbManager)
 {
   ABMultiValue *value = GetMultiValue(aOSXCard, aMap.mOSXProperty);
@@ -154,18 +155,18 @@ MapMultiValue(nsAbOSXCard *aCard, ABReco
     unsigned int j;
     unsigned int count = [value count];
     for (j = 0; j < count; ++j) {
       if ([[value labelAtIndex:j] isEqualToString:aMap.mOSXLabel]) {
         NSString *stringValue = (aMap.mOSXKey)
           ? [[value valueAtIndex:j] objectForKey:aMap.mOSXKey]
           : [value valueAtIndex:j];
         
-        SetStringProperty(aCard, stringValue, aCard->*(aMap.mProperty),
-                          aMap.mPropertyName, aNotify, aAbManager);
+        SetStringProperty(aCard, stringValue, aMap.mPropertyName, aNotify,
+                          aAbManager);
         
         return PR_TRUE;
       }
     }
   }
   
   return PR_FALSE;
 }
@@ -198,20 +199,20 @@ nsAbOSXCard::Update(PRBool aNotify)
     abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if ([card isKindOfClass:[ABGroup class]]) {
     m_IsMailList = PR_TRUE;
     m_MailListURI.AssignLiteral(NS_ABOSXDIRECTORY_URI_PREFIX);
     m_MailListURI.Append(uid);
-    MapStringProperty(this, card, kABGroupNameProperty, m_DisplayName,
-                      "DisplayName", aNotify, abManager);
-    MapStringProperty(this, card, kABGroupNameProperty, m_LastName,
-                      "LastName", aNotify, abManager);
+    MapStringProperty(this, card, kABGroupNameProperty, "DisplayName", aNotify,
+                      abManager);
+    MapStringProperty(this, card, kABGroupNameProperty, "LastName", aNotify,
+                      abManager);
 
     return NS_OK;
   }
   
   PRBool foundHome = PR_FALSE, foundWork = PR_FALSE;
   
   PRUint32 i;
   for (i = 0; i < nsAbOSXUtils::kPropertyMapSize; ++i) {
@@ -225,49 +226,56 @@ nsAbOSXCard::Update(PRBool aNotify)
         if (propertyMap.mOSXLabel == kABAddressHomeLabel) 
           foundHome = PR_TRUE;
         else
           foundWork = PR_TRUE;
       }
     }
     else {
       MapStringProperty(this, card, propertyMap.mOSXProperty,
-                        this->*(propertyMap.mProperty),
                         propertyMap.mPropertyName, aNotify, abManager);
     }
   }
   
   int flags = 0;
   if (kABPersonFlags)
     flags = [[card valueForProperty:kABPersonFlags] intValue];
   
 #define SET_STRING(_value, _name, _notify, _session) \
-  SetStringProperty(this, _value, m_##_name, #_name, _notify, _session)
+  SetStringProperty(this, _value, #_name, _notify, _session)
     
     // If kABShowAsCompany is set we use the company name as display name.
     if (kABPersonFlags && (flags & kABShowAsCompany)) {
-      SET_STRING(m_Company, DisplayName, aNotify, abManager);
+      nsString company;
+      nsresult rv = GetPropertyAsAString(kCompanyProperty, company);
+      if (NS_FAILED(rv))
+        company.Truncate();
+      SET_STRING(company, DisplayName, aNotify, abManager);
     }
   else {
     // Use the order used in the OS X address book to set DisplayName.
     int order = kABPersonFlags && (flags & kABNameOrderingMask);
     if (kABPersonFlags && (order == kABDefaultNameOrdering)) {
       order = [addressBook defaultNameOrdering];
     }
     
-    nsAutoString displayName;
+    nsAutoString displayName, tempName;
     if (kABPersonFlags && (order == kABFirstNameFirst)) {
-      displayName.Append(m_FirstName);
+      GetFirstName(tempName);
+      displayName.Append(tempName);
       displayName.Append(' ');
-      displayName.Append(m_LastName);
+      GetLastName(tempName);
+      displayName.Append(tempName);
     }
     else {
-      displayName.Append(m_LastName);
+      GetLastName(tempName);
+      displayName.Append(tempName);
       displayName.Append(' ');
-      displayName.Append(m_FirstName);
+      GetFirstName(tempName);
+      displayName.Append(tempName);
     }
     SET_STRING(displayName, DisplayName, aNotify, abManager);
   }
   
   ABMultiValue *value = GetMultiValue(card, kABEmailProperty);
   if (value) {
     unsigned int count = [value count];
     if (count > 0) {
@@ -322,18 +330,18 @@ nsAbOSXCard::Update(PRBool aNotify)
       
       if (j < count)
         SET_STRING([value valueAtIndex:j], AimScreenName, aNotify,
                    abManager);
     }
   }
   
 #define MAP_DATE(_date, _name, _notify, _session) \
-  MapDate(this, _date, m_##_name##Year, #_name"Year", m_##_name##Month, \
-#_name"Month", m_##_name##Day, #_name"Day", _notify, _session)
+  MapDate(this, _date, #_name"Year", #_name"Month", #_name"Day", _notify, \
+  _session)
     
     NSDate *date = [card valueForProperty:kABBirthdayProperty];
   if (date)
     MAP_DATE(date, Birth, aNotify, abManager);
   
   if (kABOtherDatesProperty) {
     value = GetMultiValue(card, kABOtherDatesProperty);
     if (value) {
@@ -350,13 +358,14 @@ nsAbOSXCard::Update(PRBool aNotify)
       }
     }
   }
 #undef MAP_DATE
 #undef SET_STRING
   
   date = [card valueForProperty:kABModificationDateProperty];
   if (date) 
-    m_LastModDate = PRUint32([date timeIntervalSince1970]);
+    SetPropertyAsUint32("LastModifiedDate",
+                        PRUint32([date timeIntervalSince1970]));
     // XXX No way to notify about this?
   
   return NS_OK;
 }
--- a/mailnews/addrbook/src/nsAbOSXUtils.h
+++ b/mailnews/addrbook/src/nsAbOSXUtils.h
@@ -52,17 +52,16 @@ void AppendToString(const NSString *aStr
 void AssignToString(const NSString *aString, nsString &aResult);
 void AppendToCString(const NSString *aString, nsCString &aResult);
 
 struct nsAbOSXPropertyMap
 {
     NSString * const mOSXProperty;
     NSString * const mOSXLabel;
     NSString * const mOSXKey;
-    nsString nsAbCardProperty::*mProperty;
     const char *mPropertyName;
 };
 
 class nsAbOSXUtils
 {
 public:
     static const nsAbOSXPropertyMap kPropertyMap[];
     static const PRUint32 kPropertyMapSize;
--- a/mailnews/addrbook/src/nsAbOSXUtils.mm
+++ b/mailnews/addrbook/src/nsAbOSXUtils.mm
@@ -89,17 +89,17 @@ AppendToCString(const NSString *aString,
         }
     }
 }
 
 // Some properties can't be easily mapped back and forth.
 #define DONT_MAP(moz_name, osx_property, osx_label, osx_key)
 
 #define DEFINE_PROPERTY(moz_name, osx_property, osx_label, osx_key) \
-    { osx_property, osx_label, osx_key, &nsAbOSXCard::m_##moz_name, #moz_name },
+    { osx_property, osx_label, osx_key, #moz_name },
 
 const nsAbOSXPropertyMap nsAbOSXUtils::kPropertyMap[] = {
     DEFINE_PROPERTY(FirstName, kABFirstNameProperty, nil, nil)
     DEFINE_PROPERTY(LastName, kABLastNameProperty, nil, nil)
     DONT_MAP("DisplayName", nil, nil, nil)
     DEFINE_PROPERTY(PhoneticFirstName, kABFirstNamePhoneticProperty, nil, nil)
     DEFINE_PROPERTY(PhoneticLastName, kABLastNamePhoneticProperty, nil, nil)
     DEFINE_PROPERTY(NickName, kABNicknameProperty, nil, nil)
--- a/mailnews/addrbook/src/nsAbOutlookCard.cpp
+++ b/mailnews/addrbook/src/nsAbOutlookCard.cpp
@@ -104,68 +104,68 @@ nsresult nsAbOutlookCard::Init(const cha
     mMapiData->Assign(entry) ;
     nsStringArray unichars ;
     ULONG i = 0 ;
 
     if (mapiAddBook->GetPropertiesUString(*mMapiData, OutlookCardMAPIProps, index_LastProp, unichars)) {
         SetFirstName(*unichars[index_FirstName]);
         SetLastName(*unichars[index_LastName]);
         SetDisplayName(*unichars[index_DisplayName]);
-        SetNickName(*unichars[index_NickName]);
         SetPrimaryEmail(*unichars[index_EmailAddress]);
-        SetWorkPhone(*unichars[index_WorkPhoneNumber]);
-        SetHomePhone(*unichars[index_HomePhoneNumber]);
-        SetFaxNumber(*unichars[index_WorkFaxNumber]);
-        SetPagerNumber(*unichars[index_PagerNumber]);
-        SetCellularNumber(*unichars[index_MobileNumber]);
-        SetHomeCity(*unichars[index_HomeCity]);
-        SetHomeState(*unichars[index_HomeState]);
-        SetHomeZipCode(*unichars[index_HomeZip]);
-        SetHomeCountry(*unichars[index_HomeCountry]);
-        SetWorkCity(*unichars[index_WorkCity]);
-        SetWorkState(*unichars[index_WorkState]);
-        SetWorkZipCode(*unichars[index_WorkZip]);
-        SetWorkCountry(*unichars[index_WorkCountry]);
-        SetJobTitle(*unichars[index_JobTitle]);
-        SetDepartment(*unichars[index_Department]);
-        SetCompany(*unichars[index_Company]);
-        SetWebPage1(*unichars[index_WorkWebPage]);
-        SetWebPage2(*unichars[index_HomeWebPage]);
-        SetNotes(*unichars[index_Comments]);
+        SetPropertyAsAString(kNicknameProperty, *unichars[index_NickName]);
+        SetPropertyAsAString(kWorkPhoneProperty, *unichars[index_WorkPhoneNumber]);
+        SetPropertyAsAString(kHomePhoneProperty, *unichars[index_HomePhoneNumber]);
+        SetPropertyAsAString(kFaxProperty, *unichars[index_WorkFaxNumber]);
+        SetPropertyAsAString(kPagerProperty, *unichars[index_PagerNumber]);
+        SetPropertyAsAString(kCellularProperty, *unichars[index_MobileNumber]);
+        SetPropertyAsAString(kHomeCityProperty, *unichars[index_HomeCity]);
+        SetPropertyAsAString(kHomeStateProperty, *unichars[index_HomeState]);
+        SetPropertyAsAString(kHomeZipCodeProperty, *unichars[index_HomeZip]);
+        SetPropertyAsAString(kHomeCountryProperty, *unichars[index_HomeCountry]);
+        SetPropertyAsAString(kWorkCityProperty, *unichars[index_WorkCity]);
+        SetPropertyAsAString(kWorkStateProperty, *unichars[index_WorkState]);
+        SetPropertyAsAString(kWorkZipCodeProperty, *unichars[index_WorkZip]);
+        SetPropertyAsAString(kWorkCountryProperty, *unichars[index_WorkCountry]);
+        SetPropertyAsAString(kJobTitleProperty, *unichars[index_JobTitle]);
+        SetPropertyAsAString(kDepartmentProperty, *unichars[index_Department]);
+        SetPropertyAsAString(kCompanyProperty, *unichars[index_Company]);
+        SetPropertyAsAString(kWorkWebPageProperty, *unichars[index_WorkWebPage]);
+        SetPropertyAsAString(kHomeWebPageProperty, *unichars[index_HomeWebPage]);
+        SetPropertyAsAString(kNotesProperty, *unichars[index_Comments]);
     }
     ULONG cardType = 0 ;
     nsCAutoString normalChars ;
     
     if (mapiAddBook->GetPropertyLong(*mMapiData, PR_OBJECT_TYPE, cardType)) {
         SetIsMailList(cardType == MAPI_DISTLIST) ;
         if (cardType == MAPI_DISTLIST) {
             buildAbWinUri(kOutlookDirectoryScheme, mAbWinType, normalChars) ;
             normalChars.Append(entry) ;
             SetMailListURI(normalChars.get()) ;
         }
     }
     nsAutoString unichar ;
     nsAutoString unicharBis ;
 
     if (mapiAddBook->GetPropertyUString(*mMapiData, PR_HOME_ADDRESS_STREET_W, unichar)) {
-        splitString(unichar, unicharBis) ;
-        SetHomeAddress(unichar) ;
-        SetHomeAddress2(unicharBis) ;
+        splitString(unichar, unicharBis);
+        SetPropertyAsAString(kHomeAddressProperty, unichar);
+        SetPropertyAsAString(kHomeAddress2Property, unicharBis);
     }
     if (mapiAddBook->GetPropertyUString(*mMapiData, PR_BUSINESS_ADDRESS_STREET_W, unichar)) {
-        splitString(unichar, unicharBis) ;
-        SetWorkAddress(unichar) ;
-        SetWorkAddress2(unicharBis) ;
+        splitString(unichar, unicharBis);
+        SetPropertyAsAString(kWorkAddressProperty, unichar);
+        SetPropertyAsAString(kWorkAddress2Property, unicharBis);
     }
     WORD year = 0 ;
     WORD month = 0 ;
     WORD day = 0 ;
 
     if (mapiAddBook->GetPropertyDate(*mMapiData, PR_BIRTHDAY, year, month, day)) {
         wordToUnicode(year, unichar);
-        SetBirthYear(unichar);
+        SetPropertyAsAString(kBirthYearProperty, unichar);
         wordToUnicode(month, unichar);
-        SetBirthMonth(unichar);
+        SetPropertyAsAString(kBirthMonthProperty, unichar);
         wordToUnicode(day, unichar);
-        SetBirthDay(unichar);
+        SetPropertyAsAString(kBirthDayProperty, unichar);
     }
     return retCode ;
 }
--- a/mailnews/addrbook/src/nsAbOutlookDirectory.cpp
+++ b/mailnews/addrbook/src/nsAbOutlookDirectory.cpp
@@ -524,92 +524,54 @@ NS_IMETHODIMP nsAbOutlookDirectory::Edit
 }
 
 struct OutlookTableAttr
 {
     const char *mOuterName ;
     ULONG mMapiProp ;
 } ;
 
-/*static const OutlookTableAttr OutlookTableStringToProp [] = 
-{
-{"FirstName", PR_GIVEN_NAME_W},
-{"LastName", PR_SURNAME_W},
-{"DisplayName", PR_DISPLAY_NAME_W},
-{"NickName", PR_NICKNAME_W},
-{"PrimaryEmail", PR_EMAIL_ADDRESS_W},
-{"WorkPhone", PR_BUSINESS_TELEPHONE_NUMBER_W},
-{"HomePhone", PR_HOME_TELEPHONE_NUMBER_W},
-{"FaxNumber", PR_BUSINESS_FAX_NUMBER_W},
-{"PagerNumber", PR_PAGER_TELEPHONE_NUMBER_W},
-{"CellularNumber", PR_MOBILE_TELEPHONE_NUMBER_W},
-{"HomeAddress", PR_HOME_ADDRESS_STREET_W},
-{"HomeCity", PR_HOME_ADDRESS_CITY_W},
-{"HomeState", PR_HOME_ADDRESS_STATE_OR_PROVINCE_W},
-{"HomeZipCode", PR_HOME_ADDRESS_POSTAL_CODE_W},
-{"HomeCountry", PR_HOME_ADDRESS_COUNTRY_W},
-{"WorkAddress", PR_BUSINESS_ADDRESS_STREET_W}, 
-{"WorkCity", PR_BUSINESS_ADDRESS_CITY_W},
-{"WorkState", PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_W},
-{"WorkZipCode", PR_BUSINESS_ADDRESS_POSTAL_CODE_W},
-{"WorkCountry", PR_BUSINESS_ADDRESS_COUNTRY_W},
-{"JobTitle", PR_TITLE_W},
-{"Department", PR_DEPARTMENT_NAME_W},
-{"Company", PR_COMPANY_NAME_W},
-{"WebPage1", PR_BUSINESS_HOME_PAGE_W},
-{"WebPage2", PR_PERSONAL_HOME_PAGE_W},
-// For the moment, we don't support querying on the birthday
-// sub-elements.
-#if 0
-{"BirthYear", PR_BIRTHDAY},
-{"BirthMonth", PR_BIRTHDAY}, 
-{"BirthDay", PR_BIRTHDAY},
-#endif // 0
-{"Notes", PR_COMMENT_W}
-} ;*/
-
 // Here, we are forced to use the Ascii versions of the properties
 // instead of the widechar ones, because the content restriction
 // operators do not work on unicode strings in mapi.
 static const OutlookTableAttr OutlookTableStringToProp [] = 
 {
-    // replace "PrimaryEmail" with kPriEmailColumn etc.
-    {"FirstName", PR_GIVEN_NAME_A},
-    {"LastName", PR_SURNAME_A},
-    {"DisplayName", PR_DISPLAY_NAME_A},
-    {"NickName", PR_NICKNAME_A},
-    {"PrimaryEmail", PR_EMAIL_ADDRESS_A},
-    {"WorkPhone", PR_BUSINESS_TELEPHONE_NUMBER_A},
-    {"HomePhone", PR_HOME_TELEPHONE_NUMBER_A},
-    {"FaxNumber", PR_BUSINESS_FAX_NUMBER_A},
-    {"PagerNumber", PR_PAGER_TELEPHONE_NUMBER_A},
-    {"CellularNumber", PR_MOBILE_TELEPHONE_NUMBER_A},
-    {"HomeAddress", PR_HOME_ADDRESS_STREET_A},
-    {"HomeCity", PR_HOME_ADDRESS_CITY_A},
-    {"HomeState", PR_HOME_ADDRESS_STATE_OR_PROVINCE_A},
-    {"HomeZipCode", PR_HOME_ADDRESS_POSTAL_CODE_A},
-    {"HomeCountry", PR_HOME_ADDRESS_COUNTRY_A},
-    {"WorkAddress", PR_BUSINESS_ADDRESS_STREET_A}, 
-    {"WorkCity", PR_BUSINESS_ADDRESS_CITY_A},
-    {"WorkState", PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A},
-    {"WorkZipCode", PR_BUSINESS_ADDRESS_POSTAL_CODE_A},
-    {"WorkCountry", PR_BUSINESS_ADDRESS_COUNTRY_A},
-    {"JobTitle", PR_TITLE_A},
-    {"Department", PR_DEPARTMENT_NAME_A},
-    {"Company", PR_COMPANY_NAME_A},
-    {"WebPage1", PR_BUSINESS_HOME_PAGE_A},
-    {"WebPage2", PR_PERSONAL_HOME_PAGE_A},
+    {kFirstNameProperty, PR_GIVEN_NAME_A},
+    {kLastNameProperty, PR_SURNAME_A},
+    {kDisplayNameProperty, PR_DISPLAY_NAME_A},
+    {kNicknameProperty, PR_NICKNAME_A},
+    {kPriEmailProperty, PR_EMAIL_ADDRESS_A},
+    {kWorkPhoneProperty, PR_BUSINESS_TELEPHONE_NUMBER_A},
+    {kHomePhoneProperty, PR_HOME_TELEPHONE_NUMBER_A},
+    {kFaxProperty, PR_BUSINESS_FAX_NUMBER_A},
+    {kPagerProperty, PR_PAGER_TELEPHONE_NUMBER_A},
+    {kCellularProperty, PR_MOBILE_TELEPHONE_NUMBER_A},
+    {kHomeAddressProperty, PR_HOME_ADDRESS_STREET_A},
+    {kHomeCityProperty, PR_HOME_ADDRESS_CITY_A},
+    {kHomeStateProperty, PR_HOME_ADDRESS_STATE_OR_PROVINCE_A},
+    {kHomeZipCodeProperty, PR_HOME_ADDRESS_POSTAL_CODE_A},
+    {kHomeCountryProperty, PR_HOME_ADDRESS_COUNTRY_A},
+    {kWorkAddressProperty, PR_BUSINESS_ADDRESS_STREET_A}, 
+    {kWorkCityProperty, PR_BUSINESS_ADDRESS_CITY_A},
+    {kWorkStateProperty, PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE_A},
+    {kWorkZipCodeProperty, PR_BUSINESS_ADDRESS_POSTAL_CODE_A},
+    {kWorkCountryProperty, PR_BUSINESS_ADDRESS_COUNTRY_A},
+    {kJobTitleProperty, PR_TITLE_A},
+    {kDepartmentProperty, PR_DEPARTMENT_NAME_A},
+    {kCompanyProperty, PR_COMPANY_NAME_A},
+    {kWorkWebPageProperty, PR_BUSINESS_HOME_PAGE_A},
+    {kHomeWebPageProperty, PR_PERSONAL_HOME_PAGE_A},
     // For the moment, we don't support querying on the birthday
     // sub-elements.
 #if 0
-    {"BirthYear", PR_BIRTHDAY},
-    {"BirthMonth", PR_BIRTHDAY}, 
-    {"BirthDay", PR_BIRTHDAY},
+    {kBirthYearProperty, PR_BIRTHDAY},
+    {kBirthMonthProperty, PR_BIRTHDAY}, 
+    {kBirthDayProperty, PR_BIRTHDAY},
 #endif // 0
-    {"Notes", PR_COMMENT_A}
+    {kNotesProperty, PR_COMMENT_A}
 } ;
 
 static const PRUint32 OutlookTableNbProps = sizeof(OutlookTableStringToProp) /
                                             sizeof(OutlookTableStringToProp [0]) ;
 
 static ULONG findPropertyTag(const char *aName) {
     PRUint32 i = 0 ;
     
@@ -1405,78 +1367,83 @@ NS_IMETHODIMP nsAbOutlookDirectory::Modi
                                      properties[index_DisplayName]);
     NS_ENSURE_SUCCESS(rv,rv);
 
     if (*properties[index_DisplayName].get() == 0) {
       aModifiedCard->GetPrimaryEmail(properties[index_DisplayName]);
     }
   }
   aModifiedCard->SetDisplayName(properties[index_DisplayName]);
-  aModifiedCard->GetNickName(properties[index_NickName]);
   aModifiedCard->GetPrimaryEmail(properties[index_EmailAddress]);
-  aModifiedCard->GetWorkPhone(properties[index_WorkPhoneNumber]);
-  aModifiedCard->GetHomePhone(properties[index_HomePhoneNumber]);
-  aModifiedCard->GetFaxNumber(properties[index_WorkFaxNumber]);
-  aModifiedCard->GetPagerNumber(properties[index_PagerNumber]);
-  aModifiedCard->GetCellularNumber(properties[index_MobileNumber]);
-  aModifiedCard->GetHomeCity(properties[index_HomeCity]);
-  aModifiedCard->GetHomeState(properties[index_HomeState]);
-  aModifiedCard->GetHomeZipCode(properties[index_HomeZip]);
-  aModifiedCard->GetHomeCountry(properties[index_HomeCountry]);
-  aModifiedCard->GetWorkCity(properties[index_WorkCity]);
-  aModifiedCard->GetWorkState(properties[index_WorkState]);
-  aModifiedCard->GetWorkZipCode(properties[index_WorkZip]);
-  aModifiedCard->GetWorkCountry(properties[index_WorkCountry]);
-  aModifiedCard->GetJobTitle(properties[index_JobTitle]);
-  aModifiedCard->GetDepartment(properties[index_Department]);
-  aModifiedCard->GetCompany(properties[index_Company]);
-  aModifiedCard->GetWebPage1(properties[index_WorkWebPage]);
-  aModifiedCard->GetWebPage2(properties[index_HomeWebPage]);
-  aModifiedCard->GetNotes(properties[index_Comments]);
+  aModifiedCard->GetPropertyAsAString(kNicknameProperty, properties[index_NickName]);
+  aModifiedCard->GetPropertyAsAString(kWorkPhoneProperty, properties[index_WorkPhoneNumber]);
+  aModifiedCard->GetPropertyAsAString(kHomePhoneProperty, properties[index_HomePhoneNumber]);
+  aModifiedCard->GetPropertyAsAString(kFaxProperty, properties[index_WorkFaxNumber]);
+  aModifiedCard->GetPropertyAsAString(kPagerProperty, properties[index_PagerNumber]);
+  aModifiedCard->GetPropertyAsAString(kCellularProperty, properties[index_MobileNumber]);
+  aModifiedCard->GetPropertyAsAString(kHomeCityProperty, properties[index_HomeCity]);
+  aModifiedCard->GetPropertyAsAString(kHomeStateProperty, properties[index_HomeState]);
+  aModifiedCard->GetPropertyAsAString(kHomeZipCodeProperty, properties[index_HomeZip]);
+  aModifiedCard->GetPropertyAsAString(kHomeCountryProperty, properties[index_HomeCountry]);
+  aModifiedCard->GetPropertyAsAString(kWorkCityProperty, properties[index_WorkCity]);
+  aModifiedCard->GetPropertyAsAString(kWorkStateProperty, properties[index_WorkState]);
+  aModifiedCard->GetPropertyAsAString(kWorkZipCodeProperty, properties[index_WorkZip]);
+  aModifiedCard->GetPropertyAsAString(kWorkCountryProperty, properties[index_WorkCountry]);
+  aModifiedCard->GetPropertyAsAString(kJobTitleProperty, properties[index_JobTitle]);
+  aModifiedCard->GetPropertyAsAString(kDepartmentProperty, properties[index_Department]);
+  aModifiedCard->GetPropertyAsAString(kCompanyProperty, properties[index_Company]);
+  aModifiedCard->GetPropertyAsAString(kWorkWebPageProperty, properties[index_WorkWebPage]);
+  aModifiedCard->GetPropertyAsAString(kHomeWebPageProperty, properties[index_HomeWebPage]);
+  aModifiedCard->GetPropertyAsAString(kNotesProperty, properties[index_Comments]);
   if (!mapiAddBook->SetPropertiesUString(*mMapiData, OutlookCardMAPIProps,
                                          index_LastProp, properties)) {
     PRINTF(("Cannot set general properties.\n")) ;
   }
 
   delete [] properties;
   nsString unichar;
   nsString unichar2;
   WORD year = 0;
   WORD month = 0;
   WORD day = 0;
 
-  aModifiedCard->GetHomeAddress(unichar);
-  aModifiedCard->GetHomeAddress2(unichar2);
+  aModifiedCard->GetPropertyAsAString(kHomeAddressProperty, unichar);
+  aModifiedCard->GetPropertyAsAString(kHomeAddress2Property, unichar2);
 
   utility.Assign(unichar.get());
   if (!utility.IsEmpty())
     utility.AppendLiteral("\r\n");
 
   utility.Append(unichar2.get());
   if (!mapiAddBook->SetPropertyUString(*mMapiData, PR_HOME_ADDRESS_STREET_W, utility.get())) {
     PRINTF(("Cannot set home address.\n")) ;
   }
 
-  aModifiedCard->GetWorkAddress(unichar);
-  aModifiedCard->GetWorkAddress2(unichar2);
+  unichar.Truncate();
+  aModifiedCard->GetPropertyAsAString(kWorkAddressProperty, unichar);
+  unichar2.Truncate();
+  aModifiedCard->GetPropertyAsAString(kWorkAddress2Property, unichar2);
 
   utility.Assign(unichar.get());
   if (!utility.IsEmpty())
     utility.AppendLiteral("\r\n");
 
   utility.Append(unichar2.get());
   if (!mapiAddBook->SetPropertyUString(*mMapiData, PR_BUSINESS_ADDRESS_STREET_W, utility.get())) {
     PRINTF(("Cannot set work address.\n")) ;
   }
 
-  aModifiedCard->GetBirthYear(unichar);
+  unichar.Truncate();
+  aModifiedCard->GetPropertyAsAString(kBirthYearProperty, unichar);
   UnicodeToWord(unichar.get(), year);
-  aModifiedCard->GetBirthMonth(unichar);
+  unichar.Truncate();
+  aModifiedCard->GetPropertyAsAString(kBirthMonthProperty, unichar);
   UnicodeToWord(unichar.get(), month);
-  aModifiedCard->GetBirthDay(unichar);
+  unichar.Truncate();
+  aModifiedCard->GetPropertyAsAString(kBirthDayProperty, unichar);
   UnicodeToWord(unichar.get(), day);
   if (!mapiAddBook->SetPropertyDate(*mMapiData, PR_BIRTHDAY, year, month, day)) {
     PRINTF(("Cannot set date.\n")) ;
   }
 
   return retCode;
 }
 
--- a/mailnews/addrbook/src/nsAbView.cpp
+++ b/mailnews/addrbook/src/nsAbView.cpp
@@ -436,17 +436,22 @@ nsresult nsAbView::GetCardValue(nsIAbCar
   // else, standard column (like PrimaryEmail and _AimScreenName)
   if (colID[0] == PRUnichar('G'))
     return card->GenerateName(mGeneratedNameFormat, mABBundle, _retval);
 
   if (colID[0] == PRUnichar('_') && colID[1] == PRUnichar('P'))
     // use LN/FN order for the phonetic name
     return card->GeneratePhoneticName(PR_TRUE, _retval);
 
-  return card->GetCardValue(NS_LossyConvertUTF16toASCII(colID).get(), _retval);
+  nsresult rv = card->GetPropertyAsAString(NS_ConvertUTF16toUTF8(colID).get(), _retval);
+  if (rv == NS_ERROR_NOT_AVAILABLE) {
+    rv = NS_OK;
+    _retval.Truncate();
+  }
+  return rv;
 }
 
 nsresult nsAbView::RefreshTree()
 {
   nsresult rv;
 
   // the PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST pref affects how the GeneratedName column looks.
   // so if the GeneratedName is our primary or secondary sort,
@@ -460,17 +465,17 @@ nsresult nsAbView::RefreshTree()
   //
   // one day, we can get fancy and remember what the secondary sort is.
   // we do that, we can fix this code.  at best, it will turn a sort into a invalidate.
   // 
   // if neither the primary nor the secondary sorts are GeneratedName (or kPhoneticNameColumn), 
   // all we have to do is invalidate (to show the new GeneratedNames), 
   // but the sort will not change.
   if (mSortColumn.EqualsLiteral(GENERATED_NAME_COLUMN_ID) ||
-      mSortColumn.EqualsLiteral(kPriEmailColumn) ||
+      mSortColumn.EqualsLiteral(kPriEmailProperty) ||
       mSortColumn.EqualsLiteral(kPhoneticNameColumn)) {
     rv = SortBy(mSortColumn.get(), mSortDirection.get());
   }
   else {
     rv = InvalidateTree(ALL_ROWS);
 
     // Although the selection hasn't changed, the card that is selected may need
     // to be displayed differently, therefore pretend that the selection has
@@ -764,17 +769,17 @@ nsresult nsAbView::GenerateCollationKeys
   PR_FREEIF(abcard->primaryCollationKey);
   rv = mCollationKeyGenerator->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive,
     value, &(abcard->primaryCollationKey), &(abcard->primaryCollationKeyLen));
   NS_ENSURE_SUCCESS(rv,rv);
   
   // Hardcode email to be our secondary key. As we are doing this, just call
   // the card's GetCardValue direct, rather than our own function which will
   // end up doing the same as then we can save a bit of time.
-  rv = abcard->card->GetCardValue(NS_LITERAL_CSTRING(kPriEmailColumn).get(), value);
+  rv = abcard->card->GetPrimaryEmail(value);
   NS_ENSURE_SUCCESS(rv,rv);
   
   PR_FREEIF(abcard->secondaryCollationKey);
   rv = mCollationKeyGenerator->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive,
     value, &(abcard->secondaryCollationKey), &(abcard->secondaryCollationKeyLen));
   NS_ENSURE_SUCCESS(rv,rv);
   return rv;
 }
@@ -1232,24 +1237,24 @@ NS_IMETHODIMP nsAbView::SwapFirstNameLas
             else
             {
               if (dn.Equals(dnFnLn))
                 abCard->SetDisplayName(dnLnFn);
             }
           }
 
           // swap phonetic names
-          rv = abCard->GetPhoneticFirstName(fn);
+          rv = abCard->GetPropertyAsAString(kPhoneticFirstNameProperty, fn);
           NS_ENSURE_SUCCESS(rv, rv);
-          rv = abCard->GetPhoneticLastName(ln);
+          rv = abCard->GetPropertyAsAString(kPhoneticLastNameProperty, ln);
           NS_ENSURE_SUCCESS(rv, rv);
           if (!fn.IsEmpty() || !ln.IsEmpty())
           {
-            abCard->SetPhoneticFirstName(ln);
-            abCard->SetPhoneticLastName(fn);
+            abCard->SetPropertyAsAString(kPhoneticFirstNameProperty, ln);
+            abCard->SetPropertyAsAString(kPhoneticLastNameProperty, fn);
           }
         }
       }
     }
   }
   // update the tree
   // re-sort if either generated or phonetic name is primary or secondary sort,
   // otherwise invalidate to reflect the change
--- a/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp
+++ b/mailnews/addrbook/src/nsAddbookProtocolHandler.cpp
@@ -44,17 +44,16 @@
 #include "nsAddbookProtocolHandler.h"
 
 #include "nsAddbookUrl.h"
 #include "nsAddbookProtocolHandler.h"
 #include "nsCOMPtr.h"
 #include "nsAbBaseCID.h"
 #include "nsNetUtil.h"
 #include "nsStringStream.h"
-#include "nsIAbMDBCard.h"
 #include "nsIAbDirectory.h"
 #include "nsIRDFResource.h"
 #include "nsIRDFService.h"
 #include "nsRDFCID.h"
 #include "prmem.h"
 #include "nsIAbView.h"
 #include "nsITreeView.h"
 #include "nsIStringBundle.h"
@@ -298,22 +297,22 @@ nsAddbookProtocolHandler::BuildDirectory
   NS_ENSURE_SUCCESS(rv, rv);
   treeView->GetRowCount(&numRows);
   
   for (PRInt32 row = 0; row < numRows; row++)
   {
     
     nsCOMPtr <nsIAbCard> card;
     view->GetCardFromRow(row, getter_AddRefs(card));
-    nsString xmlSubstr;
+    nsCString xmlSubstr;
 
-    rv = card->ConvertToXMLPrintData(xmlSubstr);
+    rv = card->TranslateTo(NS_LITERAL_CSTRING("xml"), xmlSubstr);
     NS_ENSURE_SUCCESS(rv,rv);
 
     aOutput.AppendLiteral("<separator/>");
-    aOutput.Append(xmlSubstr);
+    aOutput.Append(NS_ConvertUTF8toUTF16(xmlSubstr));
     aOutput.AppendLiteral("<separator/>");
   }
 
   aOutput.AppendLiteral("</directory>\n");
 
   return NS_OK;
 }
--- a/mailnews/addrbook/src/nsAddrDatabase.cpp
+++ b/mailnews/addrbook/src/nsAddrDatabase.cpp
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1999
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Pierre Phaneuf <pp@ludusdesign.com>
  *   Mark Banner <mark@standard8.demon.co.uk>
+ *   Joshua Cranmer <Pidgeot18@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -40,17 +41,16 @@
 // this file implements the nsAddrDatabase interface using the MDB Interface.
 
 #include "nsAddrDatabase.h"
 #include "nsStringGlue.h"
 #include "nsAutoPtr.h"
 #include "nsRDFCID.h"
 #include "nsUnicharUtils.h"
 #include "nsAbBaseCID.h"
-#include "nsIAbMDBCard.h"
 #include "nsIAbMDBDirectory.h"
 #include "nsServiceManagerUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsRDFCID.h"
 #include "nsMsgUtils.h"
 #include "nsMorkCID.h"
 #include "nsIMdbFactoryFactory.h"
 #include "nsIRDFService.h"
@@ -59,16 +59,18 @@
 #include "prprf.h"
 #include "nsIMutableArray.h"
 #include "nsArrayUtils.h"
 #include "nsIPromptService.h"
 #include "nsIStringBundle.h"
 #include "nsIFile.h"
 #include "nsEmbedCID.h"
 #include "nsXPCOMCIDInternal.h"
+#include "nsIProperty.h"
+#include "nsIVariant.h"
 
 #define ID_PAB_TABLE            1
 #define ID_DELETEDCARDS_TABLE           2
 
 const PRInt32 kAddressBookDBVersion = 1;
 
 static const char kPabTableKind[] = "ns:addrbk:db:table:kind:pab";
 static const char kDeletedCardsTableKind[] = "ns:addrbk:db:table:kind:deleted"; // this table is used to keep the deleted cards
@@ -80,16 +82,17 @@ static const char kDataRowScope[] = "ns:
 #define DATAROW_ROWID 1
 
 #define COLUMN_STR_MAX 16
 
 #define PURGE_CUTOFF_COUNT 50
 
 static const char kRecordKeyColumn[] = "RecordKey";
 static const char kLastRecordKeyColumn[] = "LastRecordKey";
+static const char kRowIDProperty[] = "DbRowID";
 
 static const char kMailListTotalLists[] = "ListTotalLists";    // total number of mail list in a mailing list
 static const char kLowerListNameColumn[] = "LowercaseListName";
 
 struct mdbOid gAddressBookTableOID;
 
 static const char kMailListAddressFormat[] = "Address%d";
 
@@ -1117,72 +1120,70 @@ nsresult nsAddrDatabase::InitMDBInfo()
     m_mdbTokensInitialized = PR_TRUE;
     err = m_mdbStore->StringToToken(m_mdbEnv, kCardRowScope, &m_CardRowScopeToken);
     err = m_mdbStore->StringToToken(m_mdbEnv, kListRowScope, &m_ListRowScopeToken);
     err = m_mdbStore->StringToToken(m_mdbEnv, kDataRowScope, &m_DataRowScopeToken);
     gAddressBookTableOID.mOid_Scope = m_CardRowScopeToken;
     gAddressBookTableOID.mOid_Id = ID_PAB_TABLE;
     if (NS_SUCCEEDED(err))
     {
-      m_mdbStore->StringToToken(m_mdbEnv,  kFirstNameColumn, &m_FirstNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kLastNameColumn, &m_LastNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kPhoneticFirstNameColumn, &m_PhoneticFirstNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kPhoneticLastNameColumn, &m_PhoneticLastNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kDisplayNameColumn, &m_DisplayNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kNicknameColumn, &m_NickNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kPriEmailColumn, &m_PriEmailColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kFirstNameProperty, &m_FirstNameColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kLastNameProperty, &m_LastNameColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kPhoneticFirstNameProperty, &m_PhoneticFirstNameColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kPhoneticLastNameProperty, &m_PhoneticLastNameColumnToken);
+      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,  k2ndEmailColumn, &m_2ndEmailColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kPreferMailFormatColumn, &m_MailFormatColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kPopularityIndexColumn, &m_PopularityIndexColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kAllowRemoteContentColumn, &m_AllowRemoteContentColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkPhoneColumn, &m_WorkPhoneColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomePhoneColumn, &m_HomePhoneColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kFaxColumn, &m_FaxColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kPagerColumn, &m_PagerColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCellularColumn, &m_CellularColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkPhoneTypeColumn, &m_WorkPhoneTypeColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomePhoneTypeColumn, &m_HomePhoneTypeColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kFaxTypeColumn, &m_FaxTypeColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kPagerTypeColumn, &m_PagerTypeColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCellularTypeColumn, &m_CellularTypeColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomeAddressColumn, &m_HomeAddressColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomeAddress2Column, &m_HomeAddress2ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomeCityColumn, &m_HomeCityColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomeStateColumn, &m_HomeStateColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomeZipCodeColumn, &m_HomeZipCodeColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kHomeCountryColumn, &m_HomeCountryColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkAddressColumn, &m_WorkAddressColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkAddress2Column, &m_WorkAddress2ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkCityColumn, &m_WorkCityColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkStateColumn, &m_WorkStateColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkZipCodeColumn, &m_WorkZipCodeColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWorkCountryColumn, &m_WorkCountryColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kJobTitleColumn, &m_JobTitleColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kDepartmentColumn, &m_DepartmentColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCompanyColumn, &m_CompanyColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kAimScreenNameColumn, &m_AimScreenNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kAnniversaryYearColumn, &m_AnniversaryYearColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kAnniversaryMonthColumn, &m_AnniversaryMonthColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kAnniversaryDayColumn, &m_AnniversaryDayColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kSpouseNameColumn, &m_SpouseNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kFamilyNameColumn, &m_FamilyNameColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kDefaultAddressColumn, &m_DefaultAddressColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCategoryColumn, &m_CategoryColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWebPage1Column, &m_WebPage1ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kWebPage2Column, &m_WebPage2ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kBirthYearColumn, &m_BirthYearColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kBirthMonthColumn, &m_BirthMonthColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kBirthDayColumn, &m_BirthDayColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCustom1Column, &m_Custom1ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCustom2Column, &m_Custom2ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCustom3Column, &m_Custom3ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kCustom4Column, &m_Custom4ColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kNotesColumn, &m_NotesColumnToken);
-      m_mdbStore->StringToToken(m_mdbEnv,  kLastModifiedDateColumn, &m_LastModDateColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  k2ndEmailProperty, &m_2ndEmailColumnToken);
+      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);
+      m_mdbStore->StringToToken(m_mdbEnv,  kPagerTypeProperty, &m_PagerTypeColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kCellularTypeProperty, &m_CellularTypeColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kHomeAddressProperty, &m_HomeAddressColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kHomeAddress2Property, &m_HomeAddress2ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kHomeCityProperty, &m_HomeCityColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kHomeStateProperty, &m_HomeStateColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kHomeZipCodeProperty, &m_HomeZipCodeColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kHomeCountryProperty, &m_HomeCountryColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kWorkAddressProperty, &m_WorkAddressColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kWorkAddress2Property, &m_WorkAddress2ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kWorkCityProperty, &m_WorkCityColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kWorkStateProperty, &m_WorkStateColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kWorkZipCodeProperty, &m_WorkZipCodeColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kWorkCountryProperty, &m_WorkCountryColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kJobTitleProperty, &m_JobTitleColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kDepartmentProperty, &m_DepartmentColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kCompanyProperty, &m_CompanyColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kScreenNameProperty, &m_AimScreenNameColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kAnniversaryYearProperty, &m_AnniversaryYearColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kAnniversaryMonthProperty, &m_AnniversaryMonthColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kAnniversaryDayProperty, &m_AnniversaryDayColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kSpouseNameProperty, &m_SpouseNameColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kFamilyNameProperty, &m_FamilyNameColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kWorkWebPageProperty, &m_WebPage1ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kHomeWebPageProperty, &m_WebPage2ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kBirthYearProperty, &m_BirthYearColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kBirthMonthProperty, &m_BirthMonthColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kBirthDayProperty, &m_BirthDayColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kCustom1Property, &m_Custom1ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kCustom2Property, &m_Custom2ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kCustom3Property, &m_Custom3ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kCustom4Property, &m_Custom4ColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kNotesProperty, &m_NotesColumnToken);
+      m_mdbStore->StringToToken(m_mdbEnv,  kLastModifiedDateProperty, &m_LastModDateColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kRecordKeyColumn, &m_RecordKeyColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kAddressCharSetColumn, &m_AddressCharSetColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kLastRecordKeyColumn, &m_LastRecordKeyColumnToken);
 
       err = m_mdbStore->StringToToken(m_mdbEnv, kPabTableKind, &m_PabTableKind);
 
       m_mdbStore->StringToToken(m_mdbEnv,  kMailListName, &m_ListNameColumnToken);
       m_mdbStore->StringToToken(m_mdbEnv,  kMailListNickName, &m_ListNickNameColumnToken);
@@ -1209,205 +1210,64 @@ nsresult nsAddrDatabase::AddRecordKeyCol
     UpdateLastRecordKey();
     return err;
   }
   return NS_ERROR_NULL_POINTER;
 }
 
 nsresult nsAddrDatabase::AddAttributeColumnsToRow(nsIAbCard *card, nsIMdbRow *cardRow)
 {
-  nsresult err = NS_OK;
+  nsresult rv = NS_OK;
 
   if ((!card && !cardRow) || !m_mdbEnv)
     return NS_ERROR_NULL_POINTER;
 
-  mdbOid rowOid, tableOid;
-  m_mdbPabTable->GetOid(m_mdbEnv, &tableOid);
+  mdbOid rowOid;
   cardRow->GetOid(m_mdbEnv, &rowOid);
 
-  nsCOMPtr<nsIAbMDBCard> dbcard(do_QueryInterface(card, &err));
-  if(NS_SUCCEEDED(err) && dbcard)
-  {
-    dbcard->SetDbTableID(tableOid.mOid_Id);
-    dbcard->SetDbRowID(rowOid.mOid_Id);
-  }
+  card->SetPropertyAsUint32(kRowIDProperty, rowOid.mOid_Id);
+
   // add the row to the singleton table.
   if (card && cardRow)
   {
-    nsString unicodeStr;
-    card->GetFirstName(unicodeStr);
-    AddFirstName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetLastName(unicodeStr);
-    AddLastName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetPhoneticFirstName(unicodeStr);
-    AddPhoneticFirstName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetPhoneticLastName(unicodeStr);
-    AddPhoneticLastName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetDisplayName(unicodeStr);
-    AddDisplayName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetNickName(unicodeStr);
-    AddNickName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetPrimaryEmail(unicodeStr);
-    if (!unicodeStr.IsEmpty())
-      AddUnicodeToColumn(cardRow, m_PriEmailColumnToken, m_LowerPriEmailColumnToken, unicodeStr.get());
-
-    card->GetSecondEmail(unicodeStr);
-    Add2ndEmail(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    PRUint32 format = nsIAbPreferMailFormat::unknown;
-    card->GetPreferMailFormat(&format);
-    AddPreferMailFormat(cardRow, format);
-
-    PRUint32 popularityIndex = 0;
-    card->GetPopularityIndex(&popularityIndex);
-    AddPopularityIndex(cardRow, popularityIndex);
-
-    PRBool allowRemoteContent = PR_FALSE;
-    card->GetAllowRemoteContent(&allowRemoteContent);
-    AddAllowRemoteContent(cardRow, allowRemoteContent);
-
-    card->GetWorkPhone(unicodeStr);
-    AddWorkPhone(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomePhone(unicodeStr);
-    AddHomePhone(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetFaxNumber(unicodeStr);
-    AddFaxNumber(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetPagerNumber(unicodeStr);
-    AddPagerNumber(cardRow,NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCellularNumber(unicodeStr);
-    AddCellularNumber(cardRow,NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWorkPhoneType(unicodeStr);
-    AddWorkPhoneType(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomePhoneType(unicodeStr);
-    AddHomePhoneType(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetFaxNumberType(unicodeStr);
-    AddFaxNumberType(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetPagerNumberType(unicodeStr);
-    AddPagerNumberType(cardRow,NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCellularNumberType(unicodeStr);
-    AddCellularNumberType(cardRow,NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomeAddress(unicodeStr);
-    AddHomeAddress(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomeAddress2(unicodeStr);
-    AddHomeAddress2(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomeCity(unicodeStr);
-    AddHomeCity(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomeState(unicodeStr);
-    AddHomeState(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomeZipCode(unicodeStr);
-    AddHomeZipCode(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetHomeCountry(unicodeStr);
-    AddHomeCountry(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWorkAddress(unicodeStr);
-    AddWorkAddress(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWorkAddress2(unicodeStr);
-    AddWorkAddress2(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWorkCity(unicodeStr);
-    AddWorkCity(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWorkState(unicodeStr);
-    AddWorkState(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWorkZipCode(unicodeStr);
-    AddWorkZipCode(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWorkCountry(unicodeStr);
-    AddWorkCountry(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetJobTitle(unicodeStr);
-    AddJobTitle(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetDepartment(unicodeStr);
-    AddDepartment(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCompany(unicodeStr);
-    AddCompany(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    // AimScreenName
-    card->GetAimScreenName(unicodeStr);
-    AddAimScreenName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetAnniversaryYear(unicodeStr);
-    AddAnniversaryYear(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetAnniversaryMonth(unicodeStr);
-    AddAnniversaryMonth(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetAnniversaryDay(unicodeStr);
-    AddAnniversaryDay(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetSpouseName(unicodeStr);
-    AddSpouseName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetFamilyName(unicodeStr);
-    AddFamilyName(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetDefaultAddress(unicodeStr);
-    AddDefaultAddress(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCategory(unicodeStr);
-    AddCategory(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWebPage1(unicodeStr);
-    AddWebPage1(cardRow,NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetWebPage2(unicodeStr);
-    AddWebPage2(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetBirthYear(unicodeStr);
-    AddBirthYear(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetBirthMonth(unicodeStr);
-    AddBirthMonth(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetBirthDay(unicodeStr);
-    AddBirthDay(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCustom1(unicodeStr);
-    AddCustom1(cardRow,NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCustom2(unicodeStr);
-    AddCustom2(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCustom3(unicodeStr);
-    AddCustom3(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetCustom4(unicodeStr);
-    AddCustom4(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    card->GetNotes(unicodeStr);
-    AddNotes(cardRow, NS_ConvertUTF16toUTF8(unicodeStr).get());
-
-    PRUint32 lastModDate = 0;
-    card->GetLastModifiedDate(&lastModDate);
-    AddIntColumn(cardRow, m_LastModDateColumnToken, lastModDate);
+    nsCOMPtr<nsISimpleEnumerator> properties;
+    rv = card->GetProperties(getter_AddRefs(properties));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    PRBool hasMore;
+    while (NS_SUCCEEDED(properties->HasMoreElements(&hasMore)) && hasMore)
+    {
+      nsCOMPtr<nsISupports> next;
+      rv = properties->GetNext(getter_AddRefs(next));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      nsCOMPtr<nsIProperty> prop = do_QueryInterface(next);
+      nsAutoString name;
+      prop->GetName(name);
+
+      nsCOMPtr<nsIVariant> variant;
+      prop->GetValue(getter_AddRefs(variant));
+      
+      // We can't get as a char * because that messes up UTF8 stuff
+      nsCAutoString value;
+      variant->GetAsAUTF8String(value);
+
+      mdb_token token;
+      rv = m_mdbStore->StringToToken(m_mdbEnv, NS_ConvertUTF16toUTF8(name).get(), &token);
+      NS_ENSURE_SUCCESS(rv, rv);
+ 
+      rv = AddCharStringColumn(cardRow, token, value.get());
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    // Primary email is special: it is stored lowercase as well as in its
+    // original format.
+    nsAutoString primaryEmail;
+    card->GetPrimaryEmail(primaryEmail);
+    AddPrimaryEmail(cardRow, NS_ConvertUTF16toUTF8(primaryEmail).get());
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsAddrDatabase::CreateNewCardAndAddToDB(nsIAbCard *aNewCard, PRBool aNotify /* = FALSE */, nsIAbDirectory *aParent)
 {
   nsCOMPtr <nsIMdbRow> cardRow;
@@ -1419,21 +1279,18 @@ NS_IMETHODIMP nsAddrDatabase::CreateNewC
   if (NS_SUCCEEDED(rv) && cardRow)
   {
     AddAttributeColumnsToRow(aNewCard, cardRow);
     AddRecordKeyColumnToRow(cardRow);
 
     // we need to do this for dnd
     PRUint32 key = 0;
     rv = GetIntColumn(cardRow, m_RecordKeyColumnToken, &key, 0);
-    if (NS_SUCCEEDED(rv)) {
-      nsCOMPtr<nsIAbMDBCard> dbnewCard = do_QueryInterface(aNewCard);
-      if (dbnewCard)
-        dbnewCard->SetKey(key);
-    }
+    if (NS_SUCCEEDED(rv))
+      aNewCard->SetPropertyAsUint32(kRecordKeyColumn, key);
 
     mdb_err merror = m_mdbPabTable->AddRow(m_mdbEnv, cardRow);
     if (merror != NS_OK) return NS_ERROR_FAILURE;
 
   }
   else
     return rv;
 
@@ -1522,17 +1379,17 @@ NS_IMETHODIMP nsAddrDatabase::AddListCar
   nsresult    err = NS_OK;
   nsString email;
   aPCard->GetPrimaryEmail(email);
   if (!email.IsEmpty())
   {
     nsIMdbRow    *pCardRow = nsnull;
     // Please DO NOT change the 3rd param of GetRowFromAttribute() call to
     // PR_TRUE (ie, case insensitive) without reading bugs #128535 and #121478.
-    err = GetRowFromAttribute(kPriEmailColumn, NS_ConvertUTF16toUTF8(email),
+    err = GetRowFromAttribute(kPriEmailProperty, NS_ConvertUTF16toUTF8(email),
                               PR_FALSE /* retain case */, &pCardRow);
     PRBool cardWasAdded = PR_FALSE;
     if (NS_FAILED(err) || !pCardRow)
     {
       //New Email, then add a new row with this email
       err  = GetNewRow(&pCardRow);
 
       if (NS_SUCCEEDED(err) && pCardRow)
@@ -1782,21 +1639,19 @@ NS_IMETHODIMP nsAddrDatabase::DeleteCard
   aCard->GetIsMailList(&bIsMailList);
 
   // get the right row
   nsIMdbRow* pCardRow = nsnull;
   mdbOid rowOid;
 
   rowOid.mOid_Scope = bIsMailList ? m_ListRowScopeToken : m_CardRowScopeToken;
 
-  nsCOMPtr<nsIAbMDBCard> dbcard(do_QueryInterface(aCard, &err));
+  err = aCard->GetPropertyAsUint32(kRowIDProperty, &rowOid.mOid_Id);
   NS_ENSURE_SUCCESS(err, err);
 
-  dbcard->GetDbRowID((PRUint32*)&rowOid.mOid_Id);
-
   err = m_mdbStore->GetRow(m_mdbEnv, &rowOid, &pCardRow);
   NS_ENSURE_SUCCESS(err,err);
   if (!pCardRow)
     return NS_OK;
 
   // Add the deleted card to the deletedcards table
   nsCOMPtr <nsIMdbRow> cardRow;
   AddRowToDeletedCardsTable(aCard, getter_AddRefs(cardRow));
@@ -1889,20 +1744,19 @@ NS_IMETHODIMP nsAddrDatabase::DeleteCard
 
   err = m_mdbStore->GetRow(m_mdbEnv, &listRowOid, &pListRow);
   NS_ENSURE_SUCCESS(err,err);
   if (!pListRow)
     return NS_OK;
 
   PRUint32 cardRowID;
 
-  nsCOMPtr<nsIAbMDBCard> dbcard(do_QueryInterface(card, &err));
-  if(NS_FAILED(err) || !dbcard)
+  err = card->GetPropertyAsUint32(kRowIDProperty, &cardRowID);
+  if (NS_FAILED(err))
     return NS_ERROR_NULL_POINTER;
-  dbcard->GetDbRowID(&cardRowID);
 
   err = DeleteCardFromListRow(pListRow, cardRowID);
   if (NS_SUCCEEDED(err) && aNotify) {
     NotifyCardEntryChange(AB_NotifyDeleted, card, mailList);
   }
   NS_RELEASE(pListRow);
   return NS_OK;
 }
@@ -1916,21 +1770,19 @@ NS_IMETHODIMP nsAddrDatabase::SetCardVal
     return NS_ERROR_NULL_POINTER;
 
   nsresult rv = NS_OK;
 
   nsCOMPtr <nsIMdbRow> cardRow;
   mdbOid rowOid;
   rowOid.mOid_Scope = m_CardRowScopeToken;
 
-  // XXX todo
-  // it might be that the caller always has a nsIAbMDBCard
-  nsCOMPtr<nsIAbMDBCard> dbcard = do_QueryInterface(card, &rv);
+  // it might be that the caller always has a nsAbMDBCard
+  rv = card->GetPropertyAsUint32(kRowIDProperty, &rowOid.mOid_Id);
   NS_ENSURE_SUCCESS(rv, rv);
-  dbcard->GetDbRowID((PRUint32*)&rowOid.mOid_Id);
 
   rv = m_mdbStore->GetRow(m_mdbEnv, &rowOid, getter_AddRefs(cardRow));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!cardRow)
     return NS_OK;
 
   mdb_token token;
@@ -1946,21 +1798,19 @@ NS_IMETHODIMP nsAddrDatabase::GetCardVal
     return NS_ERROR_NULL_POINTER;
 
   nsresult rv = NS_OK;
 
   nsCOMPtr <nsIMdbRow> cardRow;
   mdbOid rowOid;
   rowOid.mOid_Scope = m_CardRowScopeToken;
 
-  // XXX todo
-  // it might be that the caller always has a nsIAbMDBCard
-  nsCOMPtr<nsIAbMDBCard> dbcard = do_QueryInterface(card, &rv);
+  // it might be that the caller always has a nsAbMDBCard
+  rv = card->GetPropertyAsUint32(kRowIDProperty, &rowOid.mOid_Id);
   NS_ENSURE_SUCCESS(rv, rv);
-  dbcard->GetDbRowID((PRUint32*)&rowOid.mOid_Id);
 
   rv = m_mdbStore->GetRow(m_mdbEnv, &rowOid, getter_AddRefs(cardRow));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!cardRow) {
     *value = nsnull;
     // this can happen when adding cards when editing a mailing list
     return NS_OK;
@@ -2095,20 +1945,19 @@ NS_IMETHODIMP nsAddrDatabase::EditCard(n
 
   nsCOMPtr <nsIMdbRow> cardRow;
   mdbOid rowOid;
   rowOid.mOid_Scope = m_CardRowScopeToken;
 
   PRUint32 nowInSeconds;
   PRTime now = PR_Now();
   PRTime2Seconds(now, &nowInSeconds);
-  aCard->SetLastModifiedDate(nowInSeconds);
-  nsCOMPtr<nsIAbMDBCard> dbcard(do_QueryInterface(aCard, &err));
+  aCard->SetPropertyAsUint32(kLastModifiedDateProperty, nowInSeconds);
+  err = aCard->GetPropertyAsUint32(kRowIDProperty, &rowOid.mOid_Id);
   NS_ENSURE_SUCCESS(err, err);
-  dbcard->GetDbRowID((PRUint32*)&rowOid.mOid_Id);
 
   err = m_mdbStore->GetRow(m_mdbEnv, &rowOid, getter_AddRefs(cardRow));
   NS_ENSURE_SUCCESS(err, err);
 
   if (!cardRow)
     return NS_OK;
 
   err = AddAttributeColumnsToRow(aCard, cardRow);
@@ -2132,19 +1981,18 @@ NS_IMETHODIMP nsAddrDatabase::ContainsCa
 
     card->GetIsMailList(&bIsMailList);
 
     if (bIsMailList)
         rowOid.mOid_Scope = m_ListRowScopeToken;
     else
         rowOid.mOid_Scope = m_CardRowScopeToken;
 
-    nsCOMPtr<nsIAbMDBCard> dbcard(do_QueryInterface(card, &err));
+    err = card->GetPropertyAsUint32(kRowIDProperty, &rowOid.mOid_Id);
     NS_ENSURE_SUCCESS(err, err);
-    dbcard->GetDbRowID((PRUint32*)&rowOid.mOid_Id);
 
     err = m_mdbPabTable->HasOid(m_mdbEnv, &rowOid, &hasOid);
     if (NS_SUCCEEDED(err))
     {
         *hasCard = hasOid;
     }
 
     return err;
@@ -2277,17 +2125,17 @@ NS_IMETHODIMP nsAddrDatabase::AddLdifLis
   nsCAutoString valueString(value);
   nsCAutoString email;
   PRInt32 emailPos = valueString.Find("mail=");
   emailPos += strlen("mail=");
   email = Substring(valueString, emailPos);
   nsCOMPtr <nsIMdbRow> cardRow;
   // Please DO NOT change the 3rd param of GetRowFromAttribute() call to
   // PR_TRUE (ie, case insensitive) without reading bugs #128535 and #121478.
-  nsresult rv = GetRowFromAttribute(kPriEmailColumn, email, PR_FALSE /* retain case */,
+  nsresult rv = GetRowFromAttribute(kPriEmailProperty, email, PR_FALSE /* retain case */,
                                     getter_AddRefs(cardRow));
   if (NS_SUCCEEDED(rv) && cardRow)
   {
     mdbOid outOid;
     mdb_id rowID = 0;
     if (cardRow->GetOid(m_mdbEnv, &outOid) == NS_OK)
       rowID = outOid.mOid_Id;
 
@@ -2532,335 +2380,64 @@ nsresult nsAddrDatabase::AddLowercaseCol
     ToLowerCase(newUnicodeString);
     rv = AddCharStringColumn(row, columnToken, NS_ConvertUTF16toUTF8(newUnicodeString).get());
   }
   return rv;
 }
 
 NS_IMETHODIMP nsAddrDatabase::InitCardFromRow(nsIAbCard *newCard, nsIMdbRow* cardRow)
 {
-    nsresult    err = NS_OK;
-    if (!newCard || !cardRow)
-        return NS_ERROR_NULL_POINTER;
-
-  nsAutoString tempString;
-
-  // FIX ME
-  // there is no reason to set / copy all these attributes on the card, when we'll never even
-  // ask for them.
-    err = GetStringColumn(cardRow, m_FirstNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetFirstName(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_LastNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetLastName(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_PhoneticFirstNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetPhoneticFirstName(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_PhoneticLastNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetPhoneticLastName(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_DisplayNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetDisplayName(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_NickNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetNickName(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_PriEmailColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetPrimaryEmail(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_2ndEmailColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetSecondEmail(tempString);
-    }
-
-    PRUint32 format = nsIAbPreferMailFormat::unknown;
-    err = GetIntColumn(cardRow, m_MailFormatColumnToken, &format, 0);
-    if (NS_SUCCEEDED(err))
-        newCard->SetPreferMailFormat(format);
-
-    PRUint32 popularityIndex = 0;
-    err = GetIntColumn(cardRow, m_PopularityIndexColumnToken, &popularityIndex, 0);
-    if (NS_SUCCEEDED(err))
-        newCard->SetPopularityIndex(popularityIndex);
-
-    PRBool allowRemoteContent;
-    err = GetBoolColumn(cardRow, m_AllowRemoteContentColumnToken, &allowRemoteContent);
-    if (NS_SUCCEEDED(err))
-        newCard->SetAllowRemoteContent(allowRemoteContent);
-
-    err = GetStringColumn(cardRow, m_WorkPhoneColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
+  nsresult rv = NS_OK;
+  if (!newCard || !cardRow || !m_mdbEnv)
+    return NS_ERROR_NULL_POINTER;
+
+  nsCOMPtr<nsIMdbRowCellCursor> cursor;
+  nsCOMPtr<nsIMdbCell> cell;
+
+  rv = cardRow->GetRowCellCursor(m_mdbEnv, -1, getter_AddRefs(cursor));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  mdb_column columnNumber;
+  char columnName[100];
+  struct mdbYarn colYarn = {columnName, 0, sizeof(columnName), 0, 0, nsnull};
+  struct mdbYarn cellYarn;
+
+  do
+  {
+    rv = cursor->NextCell(m_mdbEnv, getter_AddRefs(cell), &columnNumber, nsnull);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!cell)
+      break;
+
+    // Get the value of the cell
+    cell->AliasYarn(m_mdbEnv, &cellYarn);
+    NS_ConvertUTF8toUTF16 value(static_cast<const char*>(cellYarn.mYarn_Buf),
+        cellYarn.mYarn_Fill);
+
+    if (!value.IsEmpty())
     {
-        newCard->SetWorkPhone(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_HomePhoneColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetHomePhone(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_FaxColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetFaxNumber(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_PagerColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetPagerNumber(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_CellularColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetCellularNumber(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_WorkPhoneTypeColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetWorkPhoneType(tempString);
-
-    err = GetStringColumn(cardRow, m_HomePhoneTypeColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetHomePhoneType(tempString);
-
-    err = GetStringColumn(cardRow, m_FaxTypeColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetFaxNumberType(tempString);
-
-    err = GetStringColumn(cardRow, m_PagerTypeColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetPagerNumberType(tempString);
-
-    err = GetStringColumn(cardRow, m_CellularTypeColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetCellularNumberType(tempString);
-
-    err = GetStringColumn(cardRow, m_HomeAddressColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetHomeAddress(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_HomeAddress2ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetHomeAddress2(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_HomeCityColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetHomeCity(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_HomeStateColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetHomeState(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_HomeZipCodeColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetHomeZipCode(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_HomeCountryColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetHomeCountry(tempString);
+      // Get the column of the cell
+      // Mork makes this so hard...
+      rv = m_mdbStore->TokenToString(m_mdbEnv, columnNumber, &colYarn);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      char *name = PL_strndup(static_cast<char *>(colYarn.mYarn_Buf),
+          colYarn.mYarn_Fill);
+      newCard->SetPropertyAsAString(name, value);
+      PL_strfree(name);
     }
-
-    err = GetStringColumn(cardRow, m_WorkAddressColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWorkAddress(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_WorkAddress2ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWorkAddress2(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_WorkCityColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWorkCity(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_WorkStateColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWorkState(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_WorkZipCodeColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWorkZipCode(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_WorkCountryColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWorkCountry(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_JobTitleColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetJobTitle(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_DepartmentColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetDepartment(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_CompanyColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetCompany(tempString);
-    }
-
-    // AimScreenName
-    err = GetStringColumn(cardRow, m_AimScreenNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetAimScreenName(tempString);
-
-    err = GetStringColumn(cardRow, m_AnniversaryYearColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetAnniversaryYear(tempString);
-
-    err = GetStringColumn(cardRow, m_AnniversaryMonthColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetAnniversaryMonth(tempString);
-
-    err = GetStringColumn(cardRow, m_AnniversaryDayColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetAnniversaryDay(tempString);
-
-    err = GetStringColumn(cardRow, m_SpouseNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetSpouseName(tempString);
-
-    err = GetStringColumn(cardRow, m_FamilyNameColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetFamilyName(tempString);
-
-    err = GetStringColumn(cardRow, m_DefaultAddressColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetDefaultAddress(tempString);
-
-    err = GetStringColumn(cardRow, m_CategoryColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-        newCard->SetCategory(tempString);
-
-    err = GetStringColumn(cardRow, m_WebPage1ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWebPage1(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_WebPage2ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetWebPage2(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_BirthYearColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetBirthYear(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_BirthMonthColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetBirthMonth(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_BirthDayColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetBirthDay(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_Custom1ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetCustom1(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_Custom2ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetCustom2(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_Custom3ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetCustom3(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_Custom4ColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetCustom4(tempString);
-    }
-
-    err = GetStringColumn(cardRow, m_NotesColumnToken, tempString);
-    if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
-    {
-        newCard->SetNotes(tempString);
-    }
-    PRUint32 lastModDate = 0;
-    err = GetIntColumn(cardRow, m_LastModDateColumnToken, &lastModDate, 0);
-    if (NS_SUCCEEDED(err))
-      newCard->SetLastModifiedDate(lastModDate);
-
-    PRUint32 key = 0;
-    err = GetIntColumn(cardRow, m_RecordKeyColumnToken, &key, 0);
-    if (NS_SUCCEEDED(err))
-    {
-        nsCOMPtr<nsIAbMDBCard> dbnewCard(do_QueryInterface(newCard, &err));
-        if (NS_SUCCEEDED(err) && dbnewCard)
-            dbnewCard->SetKey(key);
-    }
-
-    return err;
+  } while (true);
+ 
+  PRUint32 key = 0;
+  rv = GetIntColumn(cardRow, m_RecordKeyColumnToken, &key, 0);
+  if (NS_SUCCEEDED(rv))
+    newCard->SetPropertyAsUint32(kRecordKeyColumn, key);
+
+  return NS_OK;
 }
 
 nsresult nsAddrDatabase::GetListCardFromDB(nsIAbCard *listCard, nsIMdbRow* listRow)
 {
     nsresult    err = NS_OK;
     if (!listCard || !listRow)
         return NS_ERROR_NULL_POINTER;
 
@@ -2870,31 +2447,27 @@ nsresult nsAddrDatabase::GetListCardFrom
     if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
     {
         listCard->SetDisplayName(tempString);
         listCard->SetLastName(tempString);
     }
     err = GetStringColumn(listRow, m_ListNickNameColumnToken, tempString);
     if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
     {
-        listCard->SetNickName(tempString);
+        listCard->SetPropertyAsAString(kNicknameProperty, tempString);
     }
     err = GetStringColumn(listRow, m_ListDescriptionColumnToken, tempString);
     if (NS_SUCCEEDED(err) && !tempString.IsEmpty())
     {
-        listCard->SetNotes(tempString);
+        listCard->SetPropertyAsAString(kNotesProperty, tempString);
     }
     PRUint32 key = 0;
     err = GetIntColumn(listRow, m_RecordKeyColumnToken, &key, 0);
     if (NS_SUCCEEDED(err))
-    {
-        nsCOMPtr<nsIAbMDBCard> dblistCard(do_QueryInterface(listCard, &err));
-        if (NS_SUCCEEDED(err) && dblistCard)
-            dblistCard->SetKey(key);
-    }
+      listCard->SetPropertyAsUint32(kRecordKeyColumn, key);
     return err;
 }
 
 nsresult nsAddrDatabase::GetListFromDB(nsIAbDirectory *newList, nsIMdbRow* listRow)
 {
   nsresult    err = NS_OK;
   if (!newList || !listRow || !m_mdbStore || !m_mdbEnv)
     return NS_ERROR_NULL_POINTER;
@@ -3268,28 +2841,18 @@ nsresult nsAddrDatabase::CreateCardFromD
         rowID = outOid.mOid_Id;
 
     if(NS_SUCCEEDED(rv))
     {
         nsCOMPtr<nsIAbCard> personCard;
         personCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
         NS_ENSURE_SUCCESS(rv,rv);
 
-        nsCOMPtr<nsIAbMDBCard> dbpersonCard (do_QueryInterface(personCard, &rv));
-
-        if (NS_SUCCEEDED(rv) && dbpersonCard)
-        {
-            InitCardFromRow(personCard, cardRow);
-            mdbOid tableOid;
-            m_mdbDeletedCardsTable->GetOid(m_mdbEnv, &tableOid);
-
-            dbpersonCard->SetDbTableID(tableOid.mOid_Id);
-            dbpersonCard->SetDbRowID(rowID);
-            dbpersonCard->SetAbDatabase(this);
-        }
+        InitCardFromRow(personCard, cardRow);
+        personCard->SetPropertyAsUint32(kRowIDProperty, rowID);
 
         NS_IF_ADDREF(*result = personCard);
     }
 
     return rv;
 }
 
 nsresult nsAddrDatabase::CreateCard(nsIMdbRow* cardRow, mdb_id listRowID, nsIAbCard **result)
@@ -3306,28 +2869,18 @@ nsresult nsAddrDatabase::CreateCard(nsIM
         rowID = outOid.mOid_Id;
 
     if(NS_SUCCEEDED(rv))
     {
         nsCOMPtr<nsIAbCard> personCard;
       personCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
       NS_ENSURE_SUCCESS(rv,rv);
 
-        nsCOMPtr<nsIAbMDBCard> dbpersonCard (do_QueryInterface(personCard, &rv));
-
-        if (NS_SUCCEEDED(rv) && dbpersonCard)
-        {
-            InitCardFromRow(personCard, cardRow);
-            mdbOid tableOid;
-            m_mdbPabTable->GetOid(m_mdbEnv, &tableOid);
-
-            dbpersonCard->SetDbTableID(tableOid.mOid_Id);
-            dbpersonCard->SetDbRowID(rowID);
-            dbpersonCard->SetAbDatabase(this);
-        }
+        InitCardFromRow(personCard, cardRow);
+        personCard->SetPropertyAsUint32(kRowIDProperty, rowID);
 
         NS_IF_ADDREF(*result = personCard);
     }
 
     return rv;
 }
 
 nsresult nsAddrDatabase::CreateABCard(nsIMdbRow* cardRow, mdb_id listRowID, nsIAbCard **result)
@@ -3361,26 +2914,18 @@ nsresult nsAddrDatabase::CreateABListCar
     if(NS_SUCCEEDED(rv) && dbm_dbDirectory)
     {
     personCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
         NS_ENSURE_SUCCESS(rv,rv);
 
         if (personCard)
         {
             GetListCardFromDB(personCard, listRow);
-            mdbOid tableOid;
-            m_mdbPabTable->GetOid(m_mdbEnv, &tableOid);
-
-            nsCOMPtr<nsIAbMDBCard> dbpersonCard(do_QueryInterface(personCard, &rv));
-      if (NS_SUCCEEDED(rv) && dbpersonCard)
-      {
-              dbpersonCard->SetDbTableID(tableOid.mOid_Id);
-              dbpersonCard->SetDbRowID(rowID);
-              dbpersonCard->SetAbDatabase(this);
-      }
+
+            personCard->SetPropertyAsUint32(kRowIDProperty, rowID);
             personCard->SetIsMailList(PR_TRUE);
             personCard->SetMailListURI(listURI);
         }
 
         NS_IF_ADDREF(*result = personCard);
     }
     if (listURI)
         PR_smprintf_free(listURI);
--- a/mailnews/addrbook/test/unit/test_basic_nsIAbCard.js
+++ b/mailnews/addrbook/test/unit/test_basic_nsIAbCard.js
@@ -12,28 +12,39 @@ const kEmailValue = "testEmail\u00D2@inv
 const kEmailReducedValue = "testEmail\u00D2";
 
 function run_test() {
   // Create a new card
   var card = Components.classes["@mozilla.org/addressbook/cardproperty;1"]
                          .createInstance(Components.interfaces.nsIAbCard);
 
   // Test - Set First, Last and Display Names and Email Address
-  // via setCardValue, and check correctly saved via their
+  // via setProperty, and check correctly saved via their
   // attributes. We're using firstName to check UTF-8 values.
-  card.setCardValue("FirstName", kFNValue);
-  card.setCardValue("LastName", kLNValue);
-  card.setCardValue("DisplayName", kDNValue);
-  card.setCardValue("PrimaryEmail", kEmailValue);
+  card.setProperty("FirstName", kFNValue);
+  card.setProperty("LastName", kLNValue);
+  card.setProperty("DisplayName", kDNValue);
+  card.setProperty("PrimaryEmail", kEmailValue);
 
   do_check_eq(card.firstName, kFNValue);
   do_check_eq(card.lastName, kLNValue);
   do_check_eq(card.displayName, kDNValue);
   do_check_eq(card.primaryEmail, kEmailValue);
 
+  // Repeat in the opposite order.
+  card.firstName = kFNValue;
+  card.lastName = kLNValue;
+  card.displayName = kDNValue;
+  card.primaryEmail = kEmailValue;
+
+  do_check_eq(card.getProperty("FirstName", "BAD"), kFNValue);
+  do_check_eq(card.getProperty("LastName", "BAD"), kLNValue);
+  do_check_eq(card.getProperty("DisplayName", "BAD"), kDNValue);
+  do_check_eq(card.getProperty("PrimaryEmail", "BAD"), kEmailValue);
+
   // Test - generateName. Note: if the addressBook.properties
   // value changes, this will affect these tests.
 
   do_check_eq(card.generateName(0), kDNValue);
   do_check_eq(card.generateName(1), kLNValue + ", " + kFNValue);
   do_check_eq(card.generateName(2), kFNValue + " " + kLNValue);
 
   // Test - generateName, with missing items.
@@ -56,34 +67,34 @@ function run_test() {
 
   card.primaryEmail = "";
   do_check_eq(card.generateName(1), "");
   do_check_eq(card.generateName(2), "");
 
   // Test - generateNameWithBundle, most of this will have
   // been tested above.
 
-  card.setCardValue("FirstName", kFNValue);
-  card.setCardValue("LastName", kLNValue);
+  card.firstName = kFNValue;
+  card.lastName = kLNValue;
 
   var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
                       .getService(Components.interfaces.nsIStringBundleService);
 
   var bundle = sbs.createBundle("chrome://messenger/locale/addressbook/addressBook.properties");
 
   do_check_eq(card.generateName(1, bundle), kLNValue + ", " + kFNValue);
 
   // Test - generatePhoneticName
 
-  card.phoneticFirstName = kFNValue;
-  card.phoneticLastName = kLNValue;
+  card.setProperty("PhoneticFirstName", kFNValue);
+  card.setProperty("PhoneticLastName", kLNValue);
   do_check_eq(card.generatePhoneticName(false), kFNValue + kLNValue);
   do_check_eq(card.generatePhoneticName(true), kLNValue + kFNValue);
 
-  card.phoneticLastName = "";
+  card.setProperty("PhoneticLastName", "");
   do_check_eq(card.generatePhoneticName(false), kFNValue);
   do_check_eq(card.generatePhoneticName(true), kFNValue);
 
-  card.phoneticFirstName = "";
-  card.phoneticLastName = kLNValue;
+  card.setProperty("PhoneticFirstName", "");
+  card.setProperty("PhoneticLastName", kLNValue);
   do_check_eq(card.generatePhoneticName(false), kLNValue);
   do_check_eq(card.generatePhoneticName(true), kLNValue);
 }
--- a/mailnews/addrbook/test/unit/test_collection.js
+++ b/mailnews/addrbook/test/unit/test_collection.js
@@ -222,29 +222,29 @@ var collectChecker = {
 
   checkCardResult : function (aDetails, overrideMailFormat) {
     try {
       var card = this.AB.cardForEmailAddress(aDetails.primaryEmail);
 
       do_check_true(card != null);
 
       if ("secondEmail" in aDetails)
-        do_check_eq(card.secondEmail, aDetails.secondEmail);
+        do_check_eq(card.getProperty("SecondEmail", "BAD"), aDetails.secondEmail);
 
       if (overrideMailFormat)
-        do_check_eq(card.preferMailFormat, nsIAbPMF.unknown);
+        do_check_eq(card.getProperty("PreferMailFormat", "BAD"), nsIAbPMF.unknown);
       else if ("mailFormatOut" in aDetails)
-        do_check_eq(card.preferMailFormat, aDetails.mailFormatOut);
+        do_check_eq(card.getProperty("PreferMailFormat", "BAD"), aDetails.mailFormatOut);
       else
-        do_check_eq(card.preferMailFormat, aDetails.mailFormat);
+        do_check_eq(card.getProperty("PreferMailFormat", "BAD"), aDetails.mailFormat);
 
       do_check_eq(card.displayName, aDetails.displayName);
       do_check_eq(card.firstName, aDetails.firstName);
       do_check_eq(card.lastName, aDetails.lastName);
-      do_check_eq(card.aimScreenName, aDetails.screenName);
+      do_check_eq(card.getProperty("_AimScreenName", ""), aDetails.screenName);
     }
     catch (e) {
       throw "FAILED in checkCardResult emailHeader: " + aDetails.emailHeader + " : " + e;
     }
   }
 };
 
 function run_test()
@@ -327,16 +327,16 @@ function run_test()
   // Test - Try and modify various emails and formats.
 
   // Add a basic card with just primary and second email to allow testing
   // of the case where we don't modify when second email is matching.
   card = Components.classes["@mozilla.org/addressbook/cardproperty;1"]
                    .createInstance(Components.interfaces.nsIAbCard);
 
   card.primaryEmail = "userprim\u00D0@invalid.com";
-  card.secondEmail = "usersec\u00D0@invalid.com";
+  card.setProperty("SecondEmail", "usersec\u00D0@invalid.com");
 
   CAB.addCard(card);
 
   collectChecker.part = 0;
 
   modifyEmailChecks.forEach(collectChecker.checkAddress, collectChecker);
 };
--- a/mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch1.js
+++ b/mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch1.js
@@ -244,26 +244,26 @@ function run_test() {
     var card = childCards.getNext().QueryInterface(Ci.nsIAbCard);
 
     if (card.isMailList)
       continue;
 
     switch (card.displayName) {
     case "dis":
     case "disp":
-      card.popularityIndex = "4";
+      card.setProperty("PopularityIndex", 4);
       break;
     case "displ":
-      card.popularityIndex = "5";
+      card.setProperty("PopularityIndex", 5);
       break;
     case "d":
-      card.popularityIndex = "1";
+      card.setProperty("PopularityIndex", 1);
       break;
     case "di":
-      card.popularityIndex = "20";
+      card.setProperty("PopularityIndex", 20);
       break;
     default:
       break;
     }
 
     pab.modifyCard(card);
   }
 
--- a/mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch2.js
+++ b/mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch2.js
@@ -14,17 +14,17 @@ do_import_script("../mailnews/addrbook/s
 function createCard(chars, popularity) {
   var card = Components.classes["@mozilla.org/addressbook/cardproperty;1"]
                        .createInstance(Components.interfaces.nsIAbCard);
 
   card.firstName = "firstName".slice(0, chars);
   card.lastName = "lastName".slice(0, chars);
   card.displayName = "displayName".slice(0, chars);
   card.primaryEmail = "email".slice(0, chars) + "@invalid.com";
-  card.nickName = "nickName".slice(0, chars);
+  card.setProperty("NickName", "nickName".slice(0, chars));
 
   return card;
 }
 
 const lastSearchCards = [ createCard(1, 0), createCard(2, 0), createCard(3, 0) ];
 
 const results = [ { email: "d <e@invalid.com>", dirName: kPABData.dirName },
                   { email: "di <em@invalid.com>", dirName: kPABData.dirName },
--- a/mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch3.js
+++ b/mailnews/addrbook/test/unit/test_nsAbAutoCompleteSearch3.js
@@ -53,17 +53,17 @@ function run_test()
   var ab = abManager.getDirectory(kPABData.URI);
 
   function createAndAddCard(element) {
     var card = Cc["@mozilla.org/addressbook/cardproperty;1"]
                  .createInstance(Ci.nsIAbCard);
 
     card.primaryEmail = element.email;
     card.displayName = element.displayName;
-    card.popularityIndex = element.popularityIndex;
+    card.setProperty("PopularityIndex", element.popularityIndex);
     card.firstName = element.firstName;
 
     ab.addCard(card);
   }
 
   cards.forEach(createAndAddCard);
 
   // Test - duplicate elements
--- a/mailnews/addrbook/test/unit/test_nsIAbCard.js
+++ b/mailnews/addrbook/test/unit/test_nsIAbCard.js
@@ -33,23 +33,25 @@ function run_test() {
     // We want the one with the right email...
     if (tempCard instanceof Components.interfaces.nsIAbCard &&
         tempCard.primaryEmail == "PrimaryEmail1@test.invalid")
       fullCard = tempCard;
   }
 
   do_check_true(fullCard != null);
 
-  // Test - convertToEscapedVCard.
+  // Test - VCard.
 
-  do_check_eq(fullCard.convertToEscapedVCard(),
+  do_check_eq(fullCard.translateTo("vcard"),
               "begin%3Avcard%0D%0Afn%3ADisplayName1%0D%0An%3ALastName1%3BFirstName1%0D%0Aorg%3AOrganization1%3BDepartment1%0D%0Aadr%3AWorkAddress21%3B%3BWorkAddress1%3BWorkCity1%3BWorkState1%3BWorkZipCode1%3BWorkCountry1%0D%0Aemail%3Binternet%3APrimaryEmail1%40test.invalid%0D%0Atitle%3AJobTitle1%0D%0Atel%3Bwork%3AWorkPhone1%0D%0Atel%3Bfax%3AFaxNumber1%0D%0Atel%3Bpager%3APagerNumber1%0D%0Atel%3Bhome%3AHomePhone1%0D%0Atel%3Bcell%3ACellularNumber1%0D%0Anote%3ANotes1%0D%0Aurl%3Ahttp%3A//WebPage21%0D%0Aversion%3A2.1%0D%0Aend%3Avcard%0D%0A%0D%0A");
 
-  // Test - convertToXMLPrintData()
+  // Test - XML
 
-  do_check_eq(fullCard.convertToXMLPrintData(), "<GeneratedName>\nDisplayName1</GeneratedName>\n<table><tr><td><section><labelrow><label>Display Name: </label><DisplayName>DisplayName1</DisplayName></labelrow><labelrow><label>Nickname: </label><NickName>NickName1</NickName></labelrow><PrimaryEmail>PrimaryEmail1@test.invalid</PrimaryEmail><SecondEmail>SecondEmail1@test.invalid</SecondEmail><labelrow><label>Screen Name: </label><_AimScreenName>ScreenName1</_AimScreenName></labelrow></section></td></tr><tr><td><section><sectiontitle>Phone</sectiontitle><labelrow><label>Work: </label><WorkPhone>WorkPhone1</WorkPhone></labelrow><labelrow><label>Home: </label><HomePhone>HomePhone1</HomePhone></labelrow><labelrow><label>Fax: </label><FaxNumber>FaxNumber1</FaxNumber></labelrow><labelrow><label>Pager: </label><PagerNumber>PagerNumber1</PagerNumber></labelrow><labelrow><label>Mobile: </label><CellularNumber>CellularNumber1</CellularNumber></labelrow></section><section><sectiontitle>Other</sectiontitle><labelrow><label>Custom 1: </label><Custom1>Custom11</Custom1></labelrow><labelrow><label>Custom 2: </label><Custom2>Custom21</Custom2></labelrow><labelrow><label>Custom 3: </label><Custom3>Custom31</Custom3></labelrow><labelrow><label>Custom 4: </label><Custom4>Custom41</Custom4></labelrow><Notes>Notes1</Notes></section></td><td><section><sectiontitle>Home</sectiontitle><HomeAddress>HomeAddress11</HomeAddress><HomeAddress2>HomeAddress21</HomeAddress2><HomeCity>HomeCity1</HomeCity>, <HomeState>HomeState1</HomeState> <HomeZipCode>HomeZipCode1</HomeZipCode><HomeCountry>HomeCountry1</HomeCountry><WebPage2>http://WebPage11</WebPage2></section><section><sectiontitle>Work</sectiontitle><JobTitle>JobTitle1</JobTitle><Department>Department1</Department><Company>Organization1</Company><WorkAddress>WorkAddress1</WorkAddress><WorkAddress2>WorkAddress21</WorkAddress2><WorkCity>WorkCity1</WorkCity>, <WorkState>WorkState1</WorkState> <WorkZipCode>WorkZipCode1</WorkZipCode><WorkCountry>WorkCountry1</WorkCountry><WebPage1>http://WebPage21</WebPage1></section></td></tr></table>");
+  do_check_eq(fullCard.translateTo("xml"),
+              "<GeneratedName>\nDisplayName1</GeneratedName>\n<table><tr><td><section><labelrow><label>Display Name: </label><DisplayName>DisplayName1</DisplayName></labelrow><labelrow><label>Nickname: </label><NickName>NickName1</NickName></labelrow><PrimaryEmail>PrimaryEmail1@test.invalid</PrimaryEmail><SecondEmail>SecondEmail1@test.invalid</SecondEmail><labelrow><label>Screen Name: </label><_AimScreenName>ScreenName1</_AimScreenName></labelrow></section></td></tr><tr><td><section><sectiontitle>Phone</sectiontitle><labelrow><label>Work: </label><WorkPhone>WorkPhone1</WorkPhone></labelrow><labelrow><label>Home: </label><HomePhone>HomePhone1</HomePhone></labelrow><labelrow><label>Fax: </label><FaxNumber>FaxNumber1</FaxNumber></labelrow><labelrow><label>Pager: </label><PagerNumber>PagerNumber1</PagerNumber></labelrow><labelrow><label>Mobile: </label><CellularNumber>CellularNumber1</CellularNumber></labelrow></section><section><sectiontitle>Other</sectiontitle><labelrow><label>Custom 1: </label><Custom1>Custom11</Custom1></labelrow><labelrow><label>Custom 2: </label><Custom2>Custom21</Custom2></labelrow><labelrow><label>Custom 3: </label><Custom3>Custom31</Custom3></labelrow><labelrow><label>Custom 4: </label><Custom4>Custom41</Custom4></labelrow><Notes>Notes1</Notes></section></td><td><section><sectiontitle>Home</sectiontitle><HomeAddress>HomeAddress11</HomeAddress><HomeAddress2>HomeAddress21</HomeAddress2><HomeCity>HomeCity1</HomeCity>, <HomeState>HomeState1</HomeState> <HomeZipCode>HomeZipCode1</HomeZipCode><HomeCountry>HomeCountry1</HomeCountry><WebPage2>http://WebPage11</WebPage2></section><section><sectiontitle>Work</sectiontitle><JobTitle>JobTitle1</JobTitle><Department>Department1</Department><Company>Organization1</Company><WorkAddress>WorkAddress1</WorkAddress><WorkAddress2>WorkAddress21</WorkAddress2><WorkCity>WorkCity1</WorkCity>, <WorkState>WorkState1</WorkState> <WorkZipCode>WorkZipCode1</WorkZipCode><WorkCountry>WorkCountry1</WorkCountry><WebPage1>http://WebPage21</WebPage1></section></td></tr></table>");
 
-  // Test - convertToBase64EncodedXML()
+  // Test - base 64
 
   // btoa is only available for xpcom components or via window.btoa, so we
   // can't use it here.
-  do_check_eq(fullCard.convertToBase64EncodedXML(), "PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjw/eG1sLXN0eWxlc2hlZXQgdHlwZT0idGV4dC9jc3MiIGhyZWY9ImNocm9tZTovL21lc3Nlbmdlci9jb250ZW50L2FkZHJlc3Nib29rL3ByaW50LmNzcyI/Pgo8ZGlyZWN0b3J5Pgo8dGl0bGUgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPkFkZHJlc3MgQm9vazwvdGl0bGU+CjxHZW5lcmF0ZWROYW1lPgpEaXNwbGF5TmFtZTE8L0dlbmVyYXRlZE5hbWU+Cjx0YWJsZT48dHI+PHRkPjxzZWN0aW9uPjxsYWJlbHJvdz48bGFiZWw+RGlzcGxheSBOYW1lOiA8L2xhYmVsPjxEaXNwbGF5TmFtZT5EaXNwbGF5TmFtZTE8L0Rpc3BsYXlOYW1lPjwvbGFiZWxyb3c+PGxhYmVscm93PjxsYWJlbD5OaWNrbmFtZTogPC9sYWJlbD48Tmlja05hbWU+Tmlja05hbWUxPC9OaWNrTmFtZT48L2xhYmVscm93PjxQcmltYXJ5RW1haWw+UHJpbWFyeUVtYWlsMUB0ZXN0LmludmFsaWQ8L1ByaW1hcnlFbWFpbD48U2Vjb25kRW1haWw+U2Vjb25kRW1haWwxQHRlc3QuaW52YWxpZDwvU2Vjb25kRW1haWw+PGxhYmVscm93PjxsYWJlbD5TY3JlZW4gTmFtZTogPC9sYWJlbD48X0FpbVNjcmVlbk5hbWU+U2NyZWVuTmFtZTE8L19BaW1TY3JlZW5OYW1lPjwvbGFiZWxyb3c+PC9zZWN0aW9uPjwvdGQ+PC90cj48dHI+PHRkPjxzZWN0aW9uPjxzZWN0aW9udGl0bGU+UGhvbmU8L3NlY3Rpb250aXRsZT48bGFiZWxyb3c+PGxhYmVsPldvcms6IDwvbGFiZWw+PFdvcmtQaG9uZT5Xb3JrUGhvbmUxPC9Xb3JrUGhvbmU+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPkhvbWU6IDwvbGFiZWw+PEhvbWVQaG9uZT5Ib21lUGhvbmUxPC9Ib21lUGhvbmU+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPkZheDogPC9sYWJlbD48RmF4TnVtYmVyPkZheE51bWJlcjE8L0ZheE51bWJlcj48L2xhYmVscm93PjxsYWJlbHJvdz48bGFiZWw+UGFnZXI6IDwvbGFiZWw+PFBhZ2VyTnVtYmVyPlBhZ2VyTnVtYmVyMTwvUGFnZXJOdW1iZXI+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPk1vYmlsZTogPC9sYWJlbD48Q2VsbHVsYXJOdW1iZXI+Q2VsbHVsYXJOdW1iZXIxPC9DZWxsdWxhck51bWJlcj48L2xhYmVscm93Pjwvc2VjdGlvbj48c2VjdGlvbj48c2VjdGlvbnRpdGxlPk90aGVyPC9zZWN0aW9udGl0bGU+PGxhYmVscm93PjxsYWJlbD5DdXN0b20gMTogPC9sYWJlbD48Q3VzdG9tMT5DdXN0b20xMTwvQ3VzdG9tMT48L2xhYmVscm93PjxsYWJlbHJvdz48bGFiZWw+Q3VzdG9tIDI6IDwvbGFiZWw+PEN1c3RvbTI+Q3VzdG9tMjE8L0N1c3RvbTI+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPkN1c3RvbSAzOiA8L2xhYmVsPjxDdXN0b20zPkN1c3RvbTMxPC9DdXN0b20zPjwvbGFiZWxyb3c+PGxhYmVscm93PjxsYWJlbD5DdXN0b20gNDogPC9sYWJlbD48Q3VzdG9tND5DdXN0b200MTwvQ3VzdG9tND48L2xhYmVscm93PjxOb3Rlcz5Ob3RlczE8L05vdGVzPjwvc2VjdGlvbj48L3RkPjx0ZD48c2VjdGlvbj48c2VjdGlvbnRpdGxlPkhvbWU8L3NlY3Rpb250aXRsZT48SG9tZUFkZHJlc3M+SG9tZUFkZHJlc3MxMTwvSG9tZUFkZHJlc3M+PEhvbWVBZGRyZXNzMj5Ib21lQWRkcmVzczIxPC9Ib21lQWRkcmVzczI+PEhvbWVDaXR5PkhvbWVDaXR5MTwvSG9tZUNpdHk+LCA8SG9tZVN0YXRlPkhvbWVTdGF0ZTE8L0hvbWVTdGF0ZT4gPEhvbWVaaXBDb2RlPkhvbWVaaXBDb2RlMTwvSG9tZVppcENvZGU+PEhvbWVDb3VudHJ5PkhvbWVDb3VudHJ5MTwvSG9tZUNvdW50cnk+PFdlYlBhZ2UyPmh0dHA6Ly9XZWJQYWdlMTE8L1dlYlBhZ2UyPjwvc2VjdGlvbj48c2VjdGlvbj48c2VjdGlvbnRpdGxlPldvcms8L3NlY3Rpb250aXRsZT48Sm9iVGl0bGU+Sm9iVGl0bGUxPC9Kb2JUaXRsZT48RGVwYXJ0bWVudD5EZXBhcnRtZW50MTwvRGVwYXJ0bWVudD48Q29tcGFueT5Pcmdhbml6YXRpb24xPC9Db21wYW55PjxXb3JrQWRkcmVzcz5Xb3JrQWRkcmVzczE8L1dvcmtBZGRyZXNzPjxXb3JrQWRkcmVzczI+V29ya0FkZHJlc3MyMTwvV29ya0FkZHJlc3MyPjxXb3JrQ2l0eT5Xb3JrQ2l0eTE8L1dvcmtDaXR5PiwgPFdvcmtTdGF0ZT5Xb3JrU3RhdGUxPC9Xb3JrU3RhdGU+IDxXb3JrWmlwQ29kZT5Xb3JrWmlwQ29kZTE8L1dvcmtaaXBDb2RlPjxXb3JrQ291bnRyeT5Xb3JrQ291bnRyeTE8L1dvcmtDb3VudHJ5PjxXZWJQYWdlMT5odHRwOi8vV2ViUGFnZTIxPC9XZWJQYWdlMT48L3NlY3Rpb24+PC90ZD48L3RyPjwvdGFibGU+PC9kaXJlY3Rvcnk+Cg==");
+  do_check_eq(fullCard.translateTo("base64"),
+              "PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjw/eG1sLXN0eWxlc2hlZXQgdHlwZT0idGV4dC9jc3MiIGhyZWY9ImNocm9tZTovL21lc3Nlbmdlci9jb250ZW50L2FkZHJlc3Nib29rL3ByaW50LmNzcyI/Pgo8ZGlyZWN0b3J5Pgo8dGl0bGUgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPkFkZHJlc3MgQm9vazwvdGl0bGU+CjxHZW5lcmF0ZWROYW1lPgpEaXNwbGF5TmFtZTE8L0dlbmVyYXRlZE5hbWU+Cjx0YWJsZT48dHI+PHRkPjxzZWN0aW9uPjxsYWJlbHJvdz48bGFiZWw+RGlzcGxheSBOYW1lOiA8L2xhYmVsPjxEaXNwbGF5TmFtZT5EaXNwbGF5TmFtZTE8L0Rpc3BsYXlOYW1lPjwvbGFiZWxyb3c+PGxhYmVscm93PjxsYWJlbD5OaWNrbmFtZTogPC9sYWJlbD48Tmlja05hbWU+Tmlja05hbWUxPC9OaWNrTmFtZT48L2xhYmVscm93PjxQcmltYXJ5RW1haWw+UHJpbWFyeUVtYWlsMUB0ZXN0LmludmFsaWQ8L1ByaW1hcnlFbWFpbD48U2Vjb25kRW1haWw+U2Vjb25kRW1haWwxQHRlc3QuaW52YWxpZDwvU2Vjb25kRW1haWw+PGxhYmVscm93PjxsYWJlbD5TY3JlZW4gTmFtZTogPC9sYWJlbD48X0FpbVNjcmVlbk5hbWU+U2NyZWVuTmFtZTE8L19BaW1TY3JlZW5OYW1lPjwvbGFiZWxyb3c+PC9zZWN0aW9uPjwvdGQ+PC90cj48dHI+PHRkPjxzZWN0aW9uPjxzZWN0aW9udGl0bGU+UGhvbmU8L3NlY3Rpb250aXRsZT48bGFiZWxyb3c+PGxhYmVsPldvcms6IDwvbGFiZWw+PFdvcmtQaG9uZT5Xb3JrUGhvbmUxPC9Xb3JrUGhvbmU+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPkhvbWU6IDwvbGFiZWw+PEhvbWVQaG9uZT5Ib21lUGhvbmUxPC9Ib21lUGhvbmU+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPkZheDogPC9sYWJlbD48RmF4TnVtYmVyPkZheE51bWJlcjE8L0ZheE51bWJlcj48L2xhYmVscm93PjxsYWJlbHJvdz48bGFiZWw+UGFnZXI6IDwvbGFiZWw+PFBhZ2VyTnVtYmVyPlBhZ2VyTnVtYmVyMTwvUGFnZXJOdW1iZXI+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPk1vYmlsZTogPC9sYWJlbD48Q2VsbHVsYXJOdW1iZXI+Q2VsbHVsYXJOdW1iZXIxPC9DZWxsdWxhck51bWJlcj48L2xhYmVscm93Pjwvc2VjdGlvbj48c2VjdGlvbj48c2VjdGlvbnRpdGxlPk90aGVyPC9zZWN0aW9udGl0bGU+PGxhYmVscm93PjxsYWJlbD5DdXN0b20gMTogPC9sYWJlbD48Q3VzdG9tMT5DdXN0b20xMTwvQ3VzdG9tMT48L2xhYmVscm93PjxsYWJlbHJvdz48bGFiZWw+Q3VzdG9tIDI6IDwvbGFiZWw+PEN1c3RvbTI+Q3VzdG9tMjE8L0N1c3RvbTI+PC9sYWJlbHJvdz48bGFiZWxyb3c+PGxhYmVsPkN1c3RvbSAzOiA8L2xhYmVsPjxDdXN0b20zPkN1c3RvbTMxPC9DdXN0b20zPjwvbGFiZWxyb3c+PGxhYmVscm93PjxsYWJlbD5DdXN0b20gNDogPC9sYWJlbD48Q3VzdG9tND5DdXN0b200MTwvQ3VzdG9tND48L2xhYmVscm93PjxOb3Rlcz5Ob3RlczE8L05vdGVzPjwvc2VjdGlvbj48L3RkPjx0ZD48c2VjdGlvbj48c2VjdGlvbnRpdGxlPkhvbWU8L3NlY3Rpb250aXRsZT48SG9tZUFkZHJlc3M+SG9tZUFkZHJlc3MxMTwvSG9tZUFkZHJlc3M+PEhvbWVBZGRyZXNzMj5Ib21lQWRkcmVzczIxPC9Ib21lQWRkcmVzczI+PEhvbWVDaXR5PkhvbWVDaXR5MTwvSG9tZUNpdHk+LCA8SG9tZVN0YXRlPkhvbWVTdGF0ZTE8L0hvbWVTdGF0ZT4gPEhvbWVaaXBDb2RlPkhvbWVaaXBDb2RlMTwvSG9tZVppcENvZGU+PEhvbWVDb3VudHJ5PkhvbWVDb3VudHJ5MTwvSG9tZUNvdW50cnk+PFdlYlBhZ2UyPmh0dHA6Ly9XZWJQYWdlMTE8L1dlYlBhZ2UyPjwvc2VjdGlvbj48c2VjdGlvbj48c2VjdGlvbnRpdGxlPldvcms8L3NlY3Rpb250aXRsZT48Sm9iVGl0bGU+Sm9iVGl0bGUxPC9Kb2JUaXRsZT48RGVwYXJ0bWVudD5EZXBhcnRtZW50MTwvRGVwYXJ0bWVudD48Q29tcGFueT5Pcmdhbml6YXRpb24xPC9Db21wYW55PjxXb3JrQWRkcmVzcz5Xb3JrQWRkcmVzczE8L1dvcmtBZGRyZXNzPjxXb3JrQWRkcmVzczI+V29ya0FkZHJlc3MyMTwvV29ya0FkZHJlc3MyPjxXb3JrQ2l0eT5Xb3JrQ2l0eTE8L1dvcmtDaXR5PiwgPFdvcmtTdGF0ZT5Xb3JrU3RhdGUxPC9Xb3JrU3RhdGU+IDxXb3JrWmlwQ29kZT5Xb3JrWmlwQ29kZTE8L1dvcmtaaXBDb2RlPjxXb3JrQ291bnRyeT5Xb3JrQ291bnRyeTE8L1dvcmtDb3VudHJ5PjxXZWJQYWdlMT5odHRwOi8vV2ViUGFnZTIxPC9XZWJQYWdlMT48L3NlY3Rpb24+PC90ZD48L3RyPjwvdGFibGU+PC9kaXJlY3Rvcnk+Cg==");
 }
--- a/mailnews/base/resources/content/mailWindowOverlay.js
+++ b/mailnews/base/resources/content/mailWindowOverlay.js
@@ -2310,17 +2310,17 @@ function allowRemoteContentForSender()
     if (addrbook instanceof Components.interfaces.nsIAbMDBDirectory)
       cardForEmailAddress = addrbook.cardForEmailAddress(authorEmailAddress);
   }
 
   var allowRemoteContent = false;
   if (cardForEmailAddress && addrbook instanceof Components.interfaces.nsIAbDirectory)
   {
     // set the property for remote content
-    cardForEmailAddress.allowRemoteContent = true;
+    cardForEmailAddress.setProperty("AllowRemoteContent", true);
     addrbook.modifyCard(cardForEmailAddress);
     allowRemoteContent = true;
   }
   else
   {
     var args = {primaryEmail:authorEmailAddress, displayName:names.value[0],
                 allowRemoteContent:true};
     // create a new card and set the property
--- a/mailnews/base/resources/content/msgHdrViewOverlay.js
+++ b/mailnews/base/resources/content/msgHdrViewOverlay.js
@@ -980,17 +980,17 @@ function setFromBuddyIcon(email)
      // better to cache this?
      var myScreenName = pref.getCharPref("aim.session.screenname");
 
      if (!abAddressCollector)
        abAddressCollector = Components.classes[abAddressCollectorContractID].getService(Components.interfaces.nsIAbAddressCollecter);
 
      var card = abAddressCollector.getCardFromAttribute("PrimaryEmail", email);
 
-     if (myScreenName && card && card.aimScreenName) {
+     if (myScreenName && card && card.setProperty("_AimScreenName")) {
        if (!gIOService) {
          // lazily create these globals
          gIOService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
          gFileHandler = gIOService.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
          
          var dirService = Components.classes["@mozilla.org/file/directory_service;1"]
              .getService(Components.interfaces.nsIProperties);
          var profileDir = dirService.get("ProfD", Components.interfaces.nsIFile);
--- a/mailnews/base/src/nsMsgContentPolicy.cpp
+++ b/mailnews/base/src/nsMsgContentPolicy.cpp
@@ -43,17 +43,16 @@
 #include "nsIPrefBranch2.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsIRDFService.h"
 #include "nsIRDFResource.h"
 #include "nsIMsgHeaderParser.h"
 #include "nsIAbDirectory.h"
 #include "nsIAbMDBDirectory.h"
-#include "nsIAbMDBCard.h"
 #include "nsIAbCard.h"
 #include "nsIMsgMailNewsUrl.h"
 #include "nsIMsgWindow.h"
 #include "nsIMimeMiscStatus.h"
 #include "nsIMsgMessageService.h"
 #include "nsIMsgIncomingServer.h"
 #include "nsIRssIncomingServer.h"
 #include "nsIMsgHdr.h"
@@ -185,17 +184,17 @@ nsresult nsMsgContentPolicy::AllowRemote
     NS_ENSURE_SUCCESS(rv, rv);
     mdbDirectory = do_QueryInterface(supports);
     if (mdbDirectory)
       mdbDirectory->CardForEmailAddress(emailAddress, getter_AddRefs(cardForAddress));
   }
   
   // if we found a card from the sender, 
   if (cardForAddress)
-    cardForAddress->GetAllowRemoteContent(aAllowForSender);
+    cardForAddress->GetPropertyAsBool(kAllowRemoteContentProperty, aAllowForSender);
 
   return NS_OK;
 }
 
 /**
  * Extract the host name from aContentLocation, and look it up in our list
  * of trusted domains.
  */
--- a/mailnews/compose/src/nsMsgCompose.cpp
+++ b/mailnews/compose/src/nsMsgCompose.cpp
@@ -4565,17 +4565,17 @@ nsMsgCompose::CheckAndPopulateRecipients
                     if (NS_FAILED(rv))
                       return rv;
 
                     rv = existingCard->GetDisplayName(pDisplayName);
                     if (NS_FAILED(rv))
                       return rv;
 
                     if (bIsMailList)
-                      rv = existingCard->GetNotes(newRecipient.mEmail);
+                      rv = existingCard->GetPropertyAsAString(kNotesProperty, newRecipient.mEmail);
                     else
                       rv = existingCard->GetPrimaryEmail(newRecipient.mEmail);
 
                     if (NS_FAILED(rv))
                       return rv;
 
                     if (parser)
                       parser->MakeFullAddress(pDisplayName, newRecipient.mEmail,
@@ -4605,17 +4605,18 @@ nsMsgCompose::CheckAndPopulateRecipients
                     // recipient
                     if (bIsMailList)
                     {
                       stillNeedToSearch = PR_TRUE;
                     }
                     else
                     {
                       newRecipient.mPreferFormat = nsIAbPreferMailFormat::unknown;
-                      rv = existingCard->GetPreferMailFormat(&newRecipient.mPreferFormat);
+                      rv = existingCard->GetPropertyAsUint32(
+                          kPreferMailFormatProperty, &newRecipient.mPreferFormat);
                       if (NS_SUCCEEDED(rv))
                         newRecipient.mProcessed = PR_TRUE;
                     }
                     rv = recipientsList[i].InsertElementAt(j + 1, newRecipient) ? NS_OK : NS_ERROR_FAILURE;
                     if (NS_FAILED(rv))
                       return rv;
                   }
                   recipientsList[i].RemoveElementAt(j);
@@ -4633,32 +4634,35 @@ nsMsgCompose::CheckAndPopulateRecipients
             {
               stillNeedToSearch = PR_TRUE;
               continue;
             }
 
             // Then if we have a card for this email address
             // Please DO NOT change the 4th param of GetCardFromAttribute() call to
             // PR_TRUE (ie, case insensitive) without reading bugs #128535 and #121478.
-            rv = abDataBase->GetCardFromAttribute(abDirectory, kPriEmailColumn,
+            rv = abDataBase->GetCardFromAttribute(abDirectory, kPriEmailProperty,
                                                   NS_ConvertUTF16toUTF8(recipient.mEmail),
                                                   PR_FALSE /* case insensitive */,
                                                   getter_AddRefs(existingCard));
             if (NS_SUCCEEDED(rv) && existingCard)
             {
               recipient.mPreferFormat = nsIAbPreferMailFormat::unknown;
-              rv = existingCard->GetPreferMailFormat(&recipient.mPreferFormat);
+              rv = existingCard->GetPropertyAsUint32(kPreferMailFormatProperty,
+                                                     &recipient.mPreferFormat);
               if (NS_SUCCEEDED(rv))
                 recipient.mProcessed = PR_TRUE;
 
               // bump the popularity index for this card since we are about to send e-mail to it
               PRUint32 popularityIndex = 0;
-              if (NS_SUCCEEDED(existingCard->GetPopularityIndex(&popularityIndex)))
+              if (NS_SUCCEEDED(existingCard->GetPropertyAsUint32(
+                      kPopularityIndexProperty, &popularityIndex)))
               {
-                existingCard->SetPopularityIndex(++popularityIndex);
+                existingCard->SetPropertyAsUint32(kPopularityIndexProperty,
+                                                  ++popularityIndex);
                 // Since we are not notifying anyway, send null
                 abDataBase->EditCard(existingCard, PR_FALSE, nsnull);
 
                 // commit the database changes if we updated the popularity
                 // count.
                 abDataBase->Close(PR_TRUE);
               }
             }
--- a/mailnews/extensions/palmsync/src/nsAbIPCCard.cpp
+++ b/mailnews/extensions/palmsync/src/nsAbIPCCard.cpp
@@ -35,31 +35,31 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <windows.h>
 #include <tchar.h>
 
 #include "nsAbIPCCard.h"
 #include "nsUnicharUtils.h"
-#include "nsIAbMDBCard.h"
+#include "nsIAddrDatabase.h"
 #include "prdtoa.h"
 #include "PalmSyncImp.h"
 
 extern PRLogModuleInfo *PALMSYNC;
 
 #define CONVERT_ASSIGNTO_UNICODE(d, s, convertCRLF)  d.Truncate();\
                                         if((char*) s) d.AppendASCII((char*)s);\
                                         if (convertCRLF) \
                                           d.ReplaceSubstring(NS_LITERAL_STRING("\x0D\x0A").get(),NS_LITERAL_STRING(" ").get());
 
 #define CONVERT_CRLF_TO_SPACE(d, s) d.Assign(s); \
                                     d.ReplaceSubstring(NS_LITERAL_STRING("\x0D\x0A").get(),NS_LITERAL_STRING(" ").get());
 
-NS_IMPL_ISUPPORTS_INHERITED1(nsAbIPCCard, nsAbCardProperty, nsIAbMDBCard)
+NS_IMPL_ISUPPORTS_INHERITED0(nsAbIPCCard, nsAbCardProperty)
 
 nsAbIPCCard::nsAbIPCCard()
 {
     mRecordId = 0;
     mCategoryId = -1;
     mStatus = -1;
     PR_LOG(PALMSYNC, PR_LOG_DEBUG, ("nsAbIPCCard::nsAbIPCCard \n"));
 }
@@ -81,44 +81,39 @@ nsAbIPCCard::nsAbIPCCard(nsABCOMCardStru
     else
         ConvertToUnicodeAndCopy(card);
 }
 
 NS_IMETHODIMP nsAbIPCCard::Copy(nsIAbCard *srcCard)
 {
     NS_ENSURE_ARG_POINTER(srcCard);
 
-    nsresult rv;
-    nsCOMPtr<nsIAbMDBCard> dbCard;
-    dbCard = do_QueryInterface(srcCard, &rv);
-    if(NS_SUCCEEDED(rv) && dbCard) {
-        nsString palmIDStr;
-        nsresult rv = dbCard->GetStringAttribute(CARD_ATTRIB_PALMID, getter_Copies(palmIDStr));
-        if(NS_SUCCEEDED(rv) && !palmIDStr.IsEmpty()) {
-            PRFloat64 f = PR_strtod(NS_LossyConvertUTF16toASCII(palmIDStr).get(), nsnull);
-            PRInt64 l;
-            LL_D2L(l, f);
-            LL_L2UI(mRecordId, l);
-        }
-        else
-            mRecordId = 0;
-        // set tableID, RowID and Key for the card
-        PRUint32 tableID=0;
-        dbCard->GetDbTableID(&tableID);
-        SetDbTableID(tableID);
-        PRUint32 rowID=0;
-        dbCard->GetDbRowID(&rowID);
-        SetDbRowID(rowID);
-        PRUint32 key;
-        dbCard->GetKey(&key);
-        SetKey(key);
-    }
-    PRUint32 lastModifiedDate = 0;
-    srcCard->GetLastModifiedDate(&lastModifiedDate);
-    mStatus = (lastModifiedDate) ? ATTR_MODIFIED : ATTR_NEW;
+    nsString palmIDStr;
+    nsresult rv = srcCard->GetPropertyAsAString(CARD_ATTRIB_PALMID, palmIDStr);
+   if (NS_SUCCEEDED(rv) && !palmIDStr.IsEmpty()) {
+     PRFloat64 f = PR_strtod(NS_LossyConvertUTF16toASCII(palmIDStr).get(), nsnull);
+     PRInt64 l;
+     LL_D2L(l, f);
+     LL_L2UI(mRecordId, l);
+   }
+   else
+     mRecordId = 0;
+
+   PRUint32 rowID = 0;
+   srcCard->GetPropertyAsUint32("DbRowID", &rowID);
+   SetPropertyAsUint32("DbRowID", rowID);
+
+   PRUint32 key = 0;
+   srcCard->GetPropertyAsUint32("RecordKey", &key);
+   SetPropertyAsUint32("RecordKey", key);
+
+   PRUint32 lastModifiedDate = 0;
+   srcCard->GetPropertyAsUint32(kLastModifiedDateProperty, &lastModifiedDate);
+   mStatus = (lastModifiedDate) ? ATTR_MODIFIED : ATTR_NEW;
+
 
     rv = nsAbCardProperty::Copy(srcCard);
     // do we need to join the work and home addresses?
     // or split them?
 
     return rv;
 }
 
@@ -141,107 +136,107 @@ nsresult nsAbIPCCard::Copy(nsABCOMCardSt
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->lastName);
     SetLastName(str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->displayName);
     SetDisplayName(str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->nickName);
-    SetNickName(str);
+    SetPropertyAsAString(kNicknameProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->primaryEmail);
     SetPrimaryEmail(str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->secondEmail);
-    SetSecondEmail(str);
+    SetPropertyAsAString(k2ndEmailProperty, str);
 
-    SetPreferMailFormat(srcCard->preferMailFormat);
+    SetPropertyAsUint32(kPreferMailFormatProperty, srcCard->preferMailFormat);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->workPhone);
-    SetWorkPhone(str);
+    SetPropertyAsAString(kWorkPhoneProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->homePhone);
-    SetHomePhone(str);
+    SetPropertyAsAString(kHomePhoneProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->faxNumber);
-    SetFaxNumber(str);
+    SetPropertyAsAString(kFaxProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->pagerNumber);
-    SetPagerNumber(str);
+    SetPropertyAsAString(kPagerProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->cellularNumber);
-    SetCellularNumber(str);
+    SetPropertyAsAString(kCellularProperty, str);
 
     // See if home address contains multiple lines.
     SplitHomeAndWorkAddresses(srcCard, PR_TRUE);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->homeCity);
-    SetHomeCity(str);
+    SetPropertyAsAString(kHomeCityProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->homeState);
-    SetHomeState(str);
+    SetPropertyAsAString(kHomeStateProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->homeZipCode);
-    SetHomeZipCode(str);
+    SetPropertyAsAString(kHomeZipCodeProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->homeCountry);
-    SetHomeCountry(str);
+    SetPropertyAsAString(kHomeCountryProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->workCity);
-    SetWorkCity(str);
+    SetPropertyAsAString(kWorkCityProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->workState);
-    SetWorkState(str);
+    SetPropertyAsAString(kWorkStateProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->workZipCode);
-    SetWorkZipCode(str);
+    SetPropertyAsAString(kWorkZipCodeProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->workCountry);
-    SetWorkCountry(str);
+    SetPropertyAsAString(kWorkCountryProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->jobTitle);
-    SetJobTitle(str);
+    SetPropertyAsAString(kJobTitleProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->department);
-    SetDepartment(str);
+    SetPropertyAsAString(kDepartmentProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->company);
-    SetCompany(str);
+    SetPropertyAsAString(kCompanyProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->webPage1);
-    SetWebPage1(str);
+    SetPropertyAsAString(kWorkWebPageProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->webPage2);
-    SetWebPage2(str);
+    SetPropertyAsAString(kHomeWebPageProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->birthYear);
-    SetBirthYear(str);
+    SetPropertyAsAString(kBirthYearProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->birthMonth);
-    SetBirthMonth(str);
+    SetPropertyAsAString(kBirthMonthProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->birthDay);
-    SetBirthDay(str);
+    SetPropertyAsAString(kBirthDayProperty, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->custom1);
-    SetCustom1(str);
+    SetPropertyAsAString(kCustom1Property, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->custom2);
-    SetCustom2(str);
+    SetPropertyAsAString(kCustom2Property, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->custom3);
-    SetCustom3(str);
+    SetPropertyAsAString(kCustom3Property, str);
 
     CONVERT_CRLF_TO_SPACE(str, srcCard->custom4);
-    SetCustom4(str);
+    SetPropertyAsAString(kCustom4Property, str);
 
     str.Assign(srcCard->notes);
-    SetNotes(str);
-    SetLastModifiedDate(srcCard->lastModifiedDate);
+    SetPropertyAsAString(kNotesProperty, str);
+    SetPropertyAsUint32(kLastModifiedDateProperty, srcCard->lastModifiedDate);
     SetIsMailList(srcCard->isMailList);
     SetMailListURI(srcCard->mailListURI);
 
     return NS_OK;
 }
 
 nsresult nsAbIPCCard::ConvertToUnicodeAndCopy(nsABCOMCardStruct * srcCard)
 {
@@ -261,108 +256,108 @@ nsresult nsAbIPCCard::ConvertToUnicodeAn
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->lastName, PR_TRUE);
     SetLastName(str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->displayName, PR_TRUE);
     SetDisplayName(str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->nickName, PR_TRUE);
-    SetNickName(str);
+    SetPropertyAsAString(kNicknameProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->primaryEmail, PR_TRUE);
     SetPrimaryEmail(str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->secondEmail, PR_TRUE);
-    SetSecondEmail(str);
+    SetPropertyAsAString(k2ndEmailProperty, str);
 
-    SetPreferMailFormat(srcCard->preferMailFormat);
+    SetPropertyAsUint32(kPreferMailFormatProperty, srcCard->preferMailFormat);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->workPhone, PR_TRUE);
-    SetWorkPhone(str);
+    SetPropertyAsAString(kWorkPhoneProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->homePhone, PR_TRUE);
-    SetHomePhone(str);
+    SetPropertyAsAString(kHomePhoneProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->faxNumber, PR_TRUE);
-    SetFaxNumber(str);
+    SetPropertyAsAString(kFaxProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->pagerNumber, PR_TRUE);
-    SetPagerNumber(str);
+    SetPropertyAsAString(kPagerProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->cellularNumber, PR_TRUE);
-    SetCellularNumber(str);
+    SetPropertyAsAString(kCellularProperty, str);
 
     // See if home address contains multiple lines.
     SplitHomeAndWorkAddresses(srcCard, PR_FALSE);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->homeCity, PR_TRUE);
-    SetHomeCity(str);
+    SetPropertyAsAString(kHomeCityProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->homeState, PR_TRUE);
-    SetHomeState(str);
+    SetPropertyAsAString(kHomeStateProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->homeZipCode, PR_TRUE);
-    SetHomeZipCode(str);
+    SetPropertyAsAString(kHomeZipCodeProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->homeCountry, PR_TRUE);
-    SetHomeCountry(str);
+    SetPropertyAsAString(kHomeCountryProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->workCity, PR_TRUE);
-    SetWorkCity(str);
+    SetPropertyAsAString(kWorkCityProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->workState, PR_TRUE);
-    SetWorkState(str);
+    SetPropertyAsAString(kWorkStateProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->workZipCode, PR_TRUE);
-    SetWorkZipCode(str);
+    SetPropertyAsAString(kWorkZipCodeProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->workCountry, PR_TRUE);
-    SetWorkCountry(str);
+    SetPropertyAsAString(kWorkCountryProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->jobTitle, PR_TRUE);
-    SetJobTitle(str);
+    SetPropertyAsAString(kJobTitleProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->department, PR_TRUE);
-    SetDepartment(str);
+    SetPropertyAsAString(kDepartmentProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->company, PR_TRUE);
-    SetCompany(str);
+    SetPropertyAsAString(kCompanyProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->webPage1, PR_TRUE);
-    SetWebPage1(str);
+    SetPropertyAsAString(kWorkWebPageProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->webPage2, PR_TRUE);
-    SetWebPage2(str);
+    SetPropertyAsAString(kHomeWebPageProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->birthYear, PR_TRUE);
-    SetBirthYear(str);
+    SetPropertyAsAString(kBirthYearProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->birthMonth, PR_TRUE);
-    SetBirthMonth(str);
+    SetPropertyAsAString(kBirthMonthProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->birthDay, PR_TRUE);
-    SetBirthDay(str);
+    SetPropertyAsAString(kBirthDayProperty, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->custom1, PR_TRUE);
-    SetCustom1(str);
+    SetPropertyAsAString(kCustom1Property, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->custom2, PR_TRUE);
-    SetCustom2(str);
+    SetPropertyAsAString(kCustom2Property, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->custom3, PR_TRUE);
-    SetCustom3(str);
+    SetPropertyAsAString(kCustom3Property, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->custom4, PR_TRUE);
-    SetCustom4(str);
+    SetPropertyAsAString(kCustom4Property, str);
 
     CONVERT_ASSIGNTO_UNICODE(str, srcCard->notes, PR_FALSE);
-    SetNotes(str);
+    SetPropertyAsAString(kNotesProperty, str);
 
-    SetLastModifiedDate(srcCard->lastModifiedDate);
+    SetPropertyAsUint32(kLastModifiedDateProperty, srcCard->lastModifiedDate);
     SetIsMailList(srcCard->isMailList);
     SetMailListURI(srcCard->mailListURI);
 
     return NS_OK;
 }
 
 void nsAbIPCCard::SplitAddresses(PRBool isUnicode, LPTSTR homeAddress, LPTSTR workAddress)
 {
@@ -381,33 +376,33 @@ void nsAbIPCCard::SplitAddresses(PRBool 
   }
   nsAutoString addr1, addr2;
   if ((idx = homeAddressStr.Find( "\x0D\x0A")) != kNotFound)
   {
     homeAddressStr.Left(addr1, idx);
     homeAddressStr.Right( addr2, homeAddressStr.Length() - idx - 2);  // need to minus string lenght of CRLF.
     addr2.ReplaceSubstring(NS_LITERAL_STRING("\x0D\x0A").get(),NS_LITERAL_STRING(", ").get());
 
-    SetHomeAddress(addr1);
-    SetHomeAddress2(addr2);
+    SetPropertyAsAString(kHomeAddressProperty, addr1);
+    SetPropertyAsAString(kHomeAddress2Property, addr2);
   }
   else
-    SetHomeAddress(homeAddressStr);
+    SetPropertyAsAString(kHomeAddressProperty, homeAddressStr);
 
   if ((idx = workAddressStr.Find( "\x0D\x0A")) != kNotFound)
   {
     workAddressStr.Left(addr1, idx);
     workAddressStr.Right( addr2, workAddressStr.Length() - idx - 2);  // need to minus string lenght of CRLF.
     addr2.ReplaceSubstring(NS_LITERAL_STRING("\x0D\x0A").get(),NS_LITERAL_STRING(", ").get());
 
-    SetWorkAddress(addr1);
-    SetWorkAddress2(addr2);
+    SetPropertyAsAString(kWorkAddressProperty, addr1);
+    SetPropertyAsAString(kWorkAddress2Property, addr2);
   }
   else
-    SetWorkAddress(workAddressStr);
+    SetPropertyAsAString(kWorkAddressProperty, workAddressStr);
 }
 
 void nsAbIPCCard::SplitHomeAndWorkAddresses(nsABCOMCardStruct * card, PRBool isUnicode)
 {
   // If the address contains more than one line then split it into two 
   // (since moz only allows two address lines) and make sure all CRLFs
   // are converted to spaces in the 2nd address line. Lines are ended
   // with CRLF (done by moz conduit). So card->homeAddress2 
@@ -425,141 +420,141 @@ PRBool nsAbIPCCard::EqualsAfterUnicodeCo
     nsAbIPCCard card1(card, PR_FALSE);
     card1.SplitAddresses(PR_FALSE, card->homeAddress, card->workAddress);
     nsABCOMCardStruct * newCard = new nsABCOMCardStruct;
     // get the unicode nsABCOMCardStruct and compare
     card1.GetABCOMCardStruct(PR_TRUE, newCard);
     // want to split newCard home and work address
 
     // I think this leaks...need to free up the original values
-    card1.CopyValue(PR_TRUE, m_HomeAddress, &newCard->homeAddress);
-    card1.CopyValue(PR_TRUE, m_HomeAddress2, &newCard->homeAddress2);
-    card1.CopyValue(PR_TRUE, m_WorkAddress, &newCard->workAddress);
-    card1.CopyValue(PR_TRUE, m_WorkAddress2, &newCard->workAddress2);
+    card1.CopyValue(PR_TRUE, kHomeAddressProperty, &newCard->homeAddress);
+    card1.CopyValue(PR_TRUE, kHomeAddress2Property, &newCard->homeAddress2);
+    card1.CopyValue(PR_TRUE, kWorkAddressProperty, &newCard->workAddress);
+    card1.CopyValue(PR_TRUE, kWorkAddress2Property, &newCard->workAddress2);
   
     PRBool ret = Equals(newCard, differingAttrs);
     delete newCard;
     return ret;
 }
 
 
 PRBool nsAbIPCCard::Equals(nsABCOMCardStruct * card, nsStringArray & differingAttrs)
 {
     if(!card)
         return PR_FALSE;
 
     differingAttrs.Clear();
 
     if(card->firstName)
-        if (Compare(nsDependentString(card->firstName), m_FirstName, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kFirstNameColumn));
+        if (CompareValue(PR_TRUE, card->firstName, kFirstNameProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kFirstNameProperty));
     if(card->lastName)
-        if (Compare(nsDependentString(card->lastName), m_LastName, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kLastNameColumn));
+        if (CompareValue(PR_TRUE, card->lastName, kLastNameProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kLastNameProperty));
     if(card->displayName)
-        if (Compare(nsDependentString(card->displayName), m_DisplayName, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kDisplayNameColumn));
+        if (CompareValue(PR_TRUE, card->displayName, kDisplayNameProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kDisplayNameProperty));
     if(card->nickName)
-        if (Compare(nsDependentString(card->nickName), m_NickName, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kNicknameColumn));
+        if (CompareValue(PR_TRUE, card->nickName, kNicknameProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kNicknameProperty));
     if(card->primaryEmail)
-        if (Compare(nsDependentString(card->primaryEmail), m_PrimaryEmail, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kPriEmailColumn));
+        if (CompareValue(PR_TRUE, card->primaryEmail, kPriEmailProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kPriEmailProperty));
     if(card->secondEmail)
-        if (Compare(nsDependentString(card->secondEmail), m_SecondEmail, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(k2ndEmailColumn));
+        if (CompareValue(PR_TRUE, card->secondEmail, k2ndEmailProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(k2ndEmailProperty));
     if(card->workPhone)
-        if (Compare(nsDependentString(card->workPhone), m_WorkPhone, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkPhoneColumn));
+        if (CompareValue(PR_TRUE, card->workPhone, kWorkPhoneProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkPhoneProperty));
     if(card->homePhone)
-        if (Compare(nsDependentString(card->homePhone), m_HomePhone, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kHomePhoneColumn));
+        if (CompareValue(PR_TRUE, card->homePhone, kHomePhoneProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomePhoneProperty));
     if(card->faxNumber)
-        if (Compare(nsDependentString(card->faxNumber), m_FaxNumber, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kFaxColumn));
+        if (CompareValue(PR_TRUE, card->faxNumber, kFaxProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kFaxProperty));
     if(card->pagerNumber)
-        if (Compare(nsDependentString(card->pagerNumber), m_PagerNumber, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kPagerColumn));
+        if (CompareValue(PR_TRUE, card->pagerNumber, kPagerProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kPagerProperty));
     if(card->cellularNumber)
-        if (Compare(nsDependentString(card->cellularNumber), m_CellularNumber, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kCellularColumn));
+        if (CompareValue(PR_TRUE, card->cellularNumber, kCellularProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kCellularProperty));
     // card  has home and work addresses joined, but "this" has them split
     if(card->homeAddress)
-        if (Compare(nsDependentString(card->homeAddress), m_HomeAddress, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeAddressColumn));
+        if (CompareValue(PR_TRUE, card->homeAddress, kHomeAddressProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeAddressProperty));
     if(card->homeAddress2)
-        if (Compare(nsDependentString(card->homeAddress2), m_HomeAddress2, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeAddress2Column));
+        if (CompareValue(PR_TRUE, card->homeAddress2, kHomeAddress2Property))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeAddress2Property));
     if(card->homeCity)
-        if (Compare(nsDependentString(card->homeCity), m_HomeCity, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeCityColumn));
+        if (CompareValue(PR_TRUE, card->homeCity, kHomeCityProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeCityProperty));
     if(card->homeState)
-        if (Compare(nsDependentString(card->homeState), m_HomeState, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeStateColumn));
+        if (CompareValue(PR_TRUE, card->homeState, kHomeStateProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeStateProperty));
     if(card->homeZipCode)
-        if (Compare(nsDependentString(card->homeZipCode), m_HomeZipCode, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeZipCodeColumn));
+        if (CompareValue(PR_TRUE, card->homeZipCode, kHomeZipCodeProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeZipCodeProperty));
     if(card->homeCountry)
-        if (Compare(nsDependentString(card->homeCountry), m_HomeCountry, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeCountryColumn));
-    // card->workAddress is Joined, m_workAddress and m_workAddress2 are split
+        if (CompareValue(PR_TRUE, card->homeCountry, kHomeCountryProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeCountryProperty));
+    // card->workAddress is Joined, WorkAddress and WorkAddress2 are split
     if(card->workAddress)
-        if (Compare(nsDependentString(card->workAddress), m_WorkAddress, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkAddressColumn));
+        if (CompareValue(PR_TRUE, card->workAddress, kWorkAddressProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkAddressProperty));
     if(card->workAddress2)
-        if (Compare(nsDependentString(card->workAddress2), m_WorkAddress2, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkAddress2Column));
+        if (CompareValue(PR_TRUE, card->workAddress2, kWorkAddress2Property))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkAddress2Property));
     if(card->workCity)
-        if (Compare(nsDependentString(card->workCity), m_WorkCity, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkCityColumn));
+        if (CompareValue(PR_TRUE, card->workCity, kWorkCityProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkCityProperty));
     if(card->workState)
-        if (Compare(nsDependentString(card->workState), m_WorkState, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkStateColumn));
+        if (CompareValue(PR_TRUE, card->workState, kWorkStateProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkStateProperty));
     if(card->workZipCode)
-        if (Compare(nsDependentString(card->workZipCode), m_WorkZipCode, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkZipCodeColumn));
+        if (CompareValue(PR_TRUE, card->workZipCode, kWorkZipCodeProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkZipCodeProperty));
     if(card->workCountry)
-        if (Compare(nsDependentString(card->workCountry), m_WorkCountry, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkCountryColumn));
+        if (CompareValue(PR_TRUE, card->workCountry, kWorkCountryProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkCountryProperty));
     if(card->jobTitle)
-        if (Compare(nsDependentString(card->jobTitle), m_JobTitle, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kJobTitleColumn));
+        if (CompareValue(PR_TRUE, card->jobTitle, kJobTitleProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kJobTitleProperty));
     if(card->department)
-        if (Compare(nsDependentString(card->department), m_Department, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kDepartmentColumn));
+        if (CompareValue(PR_TRUE, card->department, kDepartmentProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kDepartmentProperty));
     if(card->company)
-        if (Compare(nsDependentString(card->company), m_Company, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kCompanyColumn));
+        if (CompareValue(PR_TRUE, card->company, kCompanyProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kCompanyProperty));
     if(card->webPage1)
-        if (Compare(nsDependentString(card->webPage1), m_WebPage1, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWebPage1Column));
+        if (CompareValue(PR_TRUE, card->webPage1, kWorkWebPageProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kWorkWebPageProperty));
     if(card->webPage2)
-        if (Compare(nsDependentString(card->webPage2), m_WebPage2, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kWebPage2Column));
+        if (CompareValue(PR_TRUE, card->webPage2, kWorkWebPageProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kHomeWebPageProperty));
     if(card->birthYear)
-        if (Compare(nsDependentString(card->birthYear), m_BirthYear, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kBirthYearColumn));
+        if (CompareValue(PR_TRUE, card->birthYear, kBirthYearProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kBirthYearProperty));
     if(card->birthMonth)
-        if (Compare(nsDependentString(card->birthMonth), m_BirthMonth, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kBirthMonthColumn));
+        if (CompareValue(PR_TRUE, card->birthMonth, kBirthMonthProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kBirthMonthProperty));
     if(card->birthDay)
-        if (Compare(nsDependentString(card->birthDay), m_BirthDay, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kBirthDayColumn));
+        if (CompareValue(PR_TRUE, card->birthDay, kBirthDayProperty))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kBirthDayProperty));
     if(card->custom1)
-        if (Compare(nsDependentString(card->custom1), m_Custom1, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom1Column));
+        if (CompareValue(PR_TRUE, card->custom1, kCustom1Property))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom1Property));
     if(card->custom2)
-        if (Compare(nsDependentString(card->custom2), m_Custom2, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom2Column));
+        if (CompareValue(PR_TRUE, card->custom2, kCustom2Property))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom2Property));
     if(card->custom3)
-        if (Compare(nsDependentString(card->custom3), m_Custom3, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom3Column));
+        if (CompareValue(PR_TRUE, card->custom3, kCustom3Property))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom3Property));
     if(card->custom4)
-        if (Compare(nsDependentString(card->custom4), m_Custom4, nsCaseInsensitiveStringComparator()))
-            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom4Column));
+        if (CompareValue(PR_TRUE, card->custom4, kCustom4Property))
+            differingAttrs.AppendString(NS_LITERAL_STRING(kCustom4Property));
     if (card->isMailList != m_IsMailList)
         differingAttrs.AppendString(NS_LITERAL_STRING(kMailListName));
     if(card->mailListURI) {
         nsCAutoString str(card->mailListURI);
         if (str.Equals(m_MailListURI, nsCaseInsensitiveCStringComparator()))
             differingAttrs.AppendString(NS_LITERAL_STRING(kMailListDescription));
     }
 
@@ -571,250 +566,286 @@ NS_IMETHODIMP nsAbIPCCard::Equals(nsIAbC
 {
     NS_ENSURE_ARG_POINTER(card);
     NS_ENSURE_ARG_POINTER(_retval);
 
     nsString str;
     *_retval = PR_FALSE;
 
     card->GetFirstName(str);
-    if (Compare(str, m_FirstName, nsCaseInsensitiveStringComparator()))
+    if (Compare(str, kFirstNameProperty))
         return NS_OK;
 
     card->GetLastName(str);
-    if (Compare(str, m_LastName, nsCaseInsensitiveStringComparator()))
+    if (Compare(str, kLastNameProperty))
         return NS_OK;
 
     card->GetDisplayName(str);
-    if (Compare(str, m_DisplayName, nsCaseInsensitiveStringComparator()))
+    if (Compare(str, kDisplayNameProperty))
         return NS_OK;
 
-    card->GetNickName(str);
-    if (Compare(str, m_NickName, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kNicknameProperty, str)))
+      str.Truncate();
+    if (Compare(str, kNicknameProperty))
         return NS_OK;
 
     card->GetPrimaryEmail(str);
-    if (Compare(str, m_PrimaryEmail, nsCaseInsensitiveStringComparator()))
+    if (Compare(str, kPriEmailProperty))
         return NS_OK;
 
-    card->GetSecondEmail(str);
-    if (Compare(str, m_SecondEmail, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(k2ndEmailProperty, str)))
+      str.Truncate();
+    if (Compare(str, k2ndEmailProperty))
         return NS_OK;
 
-    card->GetWorkPhone(str);
-    if (Compare(str, m_WorkPhone, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkPhoneProperty, str)))
+      str.Truncate();
+    if (Compare(str, kWorkPhoneProperty))
         return NS_OK;
 
-    card->GetHomePhone(str);
-    if (Compare(str, m_HomePhone, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomePhoneProperty, str)))
+      str.Truncate();
+    if (Compare(str, kHomePhoneProperty))
         return NS_OK;
 
-    card->GetFaxNumber(str);
-    if (Compare(str, m_FaxNumber, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kFaxProperty, str)))
+      str.Truncate();
+    if (Compare(str, kFaxProperty))
         return NS_OK;
 
-    card->GetPagerNumber(str);
-    if (Compare(str, m_PagerNumber, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kPagerProperty, str)))
+      str.Truncate();
+    if (Compare(str, kPagerProperty))
         return NS_OK;
 
-    card->GetCellularNumber(str);
-    if (Compare(str, m_CellularNumber, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kCellularProperty, str)))
+      str.Truncate();
+    if (Compare(str, kCellularProperty))
         return NS_OK;
 
-    card->GetHomeAddress(str);
-    if (Compare(str, m_HomeAddress, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomeAddressProperty, str)))
+      str.Truncate();
+    if (Compare(str, kHomeAddressProperty))
         return NS_OK;
 
-    card->GetHomeAddress2(str);
-    if (Compare(str, m_HomeAddress2, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomeAddress2Property, str)))
+      str.Truncate();
+    if (Compare(str, kHomeAddress2Property))
         return NS_OK;
 
-    card->GetHomeCity(str);
-    if (Compare(str, m_HomeCity, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomeCityProperty, str)))
+      str.Truncate();
+    if (Compare(str, kHomeCityProperty))
         return NS_OK;
 
-    card->GetHomeState(str);
-    if (Compare(str, m_HomeState, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomeStateProperty, str)))
+      str.Truncate();
+    if (Compare(str, kHomeStateProperty))
         return NS_OK;
 
-    card->GetHomeZipCode(str);
-    if (Compare(str, m_HomeZipCode, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomeZipCodeProperty, str)))
+      str.Truncate();
+    if (Compare(str, kHomeZipCodeProperty))
         return NS_OK;
 
-    card->GetHomeCountry(str);
-    if (Compare(str, m_HomeCountry, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomeCountryProperty, str)))
+      str.Truncate();
+    if (Compare(str, kHomeCountryProperty))
         return NS_OK;
 
     // both card and this have their addresses split, which is correct
-    card->GetWorkAddress(str);
-    if (Compare(str, m_WorkAddress, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkAddressProperty, str)))
+      str.Truncate();
+    if (Compare(str, kWorkAddressProperty))
         return NS_OK;
 
-    card->GetWorkAddress2(str);
-    if (Compare(str, m_WorkAddress2, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkAddress2Property, str)))
+      str.Truncate();
+    if (Compare(str, kWorkAddress2Property))
         return NS_OK;
 
-    card->GetWorkCity(str);
-    if (Compare(str, m_WorkCity, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkCityProperty, str)))
+      str.Truncate();
+    if (Compare(str, kWorkCityProperty))
         return NS_OK;
 
-    card->GetWorkState(str);
-    if (Compare(str, m_WorkState, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkStateProperty, str)))
+      str.Truncate();
+    if (Compare(str, kWorkStateProperty))
         return NS_OK;
 
-    card->GetWorkZipCode(str);
-    if (Compare(str, m_WorkZipCode, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkZipCodeProperty, str)))
+      str.Truncate();
+    if (Compare(str, kWorkZipCodeProperty))
         return NS_OK;
 
-    card->GetWorkCountry(str);
-    if (Compare(str, m_WorkCountry, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkCountryProperty, str)))
+      str.Truncate();
+    if (Compare(str, kWorkCountryProperty))
         return NS_OK;
 
-    card->GetJobTitle(str);
-    if (Compare(str, m_JobTitle, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kJobTitleProperty, str)))
+      str.Truncate();
+    if (Compare(str, kJobTitleProperty))
         return NS_OK;
 
-    card->GetDepartment(str);
-    if (Compare(str, m_Department, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kDepartmentProperty, str)))
+      str.Truncate();
+    if (Compare(str, kDepartmentProperty))
         return NS_OK;
 
-    card->GetCompany(str);
-    if (Compare(str, m_Company, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kCompanyProperty, str)))
+      str.Truncate();
+    if (Compare(str, kCompanyProperty))
         return NS_OK;
 
-    card->GetWebPage1(str);
-    if (Compare(str, m_WebPage1, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kWorkWebPageProperty, str)))
+      str.Truncate();
+    if (Compare(str, kWorkWebPageProperty))
         return NS_OK;
 
-    card->GetWebPage2(str);
-    if (Compare(str, m_WebPage2, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kHomeWebPageProperty, str)))
+      str.Truncate();
+    if (Compare(str, kHomeWebPageProperty))
         return NS_OK;
 
-    card->GetBirthYear(str);
-    if (Compare(str, m_BirthYear, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kBirthYearProperty, str)))
+      str.Truncate();
+    if (Compare(str, kBirthYearProperty))
         return NS_OK;
 
-    card->GetBirthMonth(str);
-    if (Compare(str, m_BirthMonth, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kBirthMonthProperty, str)))
+      str.Truncate();
+    if (Compare(str, kBirthMonthProperty))
         return NS_OK;
 
-    card->GetBirthDay(str);
-    if (Compare(str, m_BirthDay, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kBirthDayProperty, str)))
+      str.Truncate();
+    if (Compare(str, kBirthDayProperty))
         return NS_OK;
 
-    card->GetCustom1(str);
-    if (Compare(str, m_Custom1, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kCustom1Property, str)))
+      str.Truncate();
+    if (Compare(str, kCustom1Property))
         return NS_OK;
 
-    card->GetCustom2(str);
-    if (Compare(str, m_Custom2, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kCustom2Property, str)))
+      str.Truncate();
+    if (Compare(str, kCustom2Property))
         return NS_OK;
 
-    card->GetCustom3(str);
-    if (Compare(str, m_Custom3, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kCustom3Property, str)))
+      str.Truncate();
+    if (Compare(str, kCustom3Property))
         return NS_OK;
 
-    card->GetCustom4(str);
-    if (Compare(str, m_Custom4, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kCustom4Property, str)))
+      str.Truncate();
+    if (Compare(str, kCustom4Property))
         return NS_OK;
 
     PRBool isMailList=PR_FALSE;
     card->GetIsMailList(&isMailList);
     if (isMailList != m_IsMailList)
         return NS_OK;
 
     nsCString str2;
     card->GetMailListURI(getter_Copies(str2));
     if (m_MailListURI.Equals(str2, nsCaseInsensitiveCStringComparator()))
         return NS_OK;
 
     *_retval = PR_TRUE;
     return NS_OK;
 }
 
-PRBool nsAbIPCCard::CompareValue(PRBool isUnicode, LPTSTR cardValue, nsString & attribValue)
+PRBool nsAbIPCCard::CompareValue(PRBool isUnicode, LPTSTR cardValue, const char *attribute)
 {
     if(cardValue) {
         if(isUnicode) {
-            if (Compare(nsDependentString(cardValue), attribValue, nsCaseInsensitiveStringComparator()))
+            if (Compare(nsDependentString(cardValue), attribute))
                 return PR_FALSE;
         }
         else {
             nsAutoString str;
             CONVERT_ASSIGNTO_UNICODE(str, cardValue, PR_TRUE);
-            if (Compare(str, attribValue, nsCaseInsensitiveStringComparator()))
+            if (Compare(str, attribute))
                 return PR_FALSE;
         }
     }
 
     return PR_TRUE;
 }
 
+PRBool nsAbIPCCard::Compare(nsString &cardValue, const char *attribute)
+{
+  nsAutoString attribValue;
+  GetPropertyAsAString(attribute, attribValue);
+  return ::Compare(cardValue, attribValue, nsCaseInsensitiveStringComparator());
+}
 PRBool nsAbIPCCard::Same(nsABCOMCardStruct * card, PRBool isUnicode)
 {
     if(!card)
         return PR_FALSE;
 
     if(mRecordId && card->dwRecordId) 
         return (mRecordId == card->dwRecordId);
 
-    if(CompareValue(isUnicode, card->firstName, m_FirstName))
-        if(CompareValue(isUnicode, card->lastName, m_LastName))
-            if(CompareValue(isUnicode, card->displayName, m_DisplayName))
-                if(CompareValue(isUnicode, card->nickName, m_NickName))
+    if(CompareValue(isUnicode, card->firstName, kFirstNameProperty))
+        if(CompareValue(isUnicode, card->lastName, kLastNameProperty))
+            if(CompareValue(isUnicode, card->displayName, kDisplayNameProperty))
+                if(CompareValue(isUnicode, card->nickName, kNicknameProperty))
                     return PR_TRUE;
 
     return PR_FALSE;
 }
 
 
 PRBool nsAbIPCCard::Same(nsIAbCard *card)
 {
     if(!card)
         return PR_FALSE;
 
     nsresult rv;
-    nsCOMPtr<nsIAbMDBCard> dbCard;
-    dbCard = do_QueryInterface(card, &rv);
-    if(NS_SUCCEEDED(rv)) {
-        // first check the palmID for the cards if they exist
-        nsString palmIDStr;
-        rv = dbCard->GetStringAttribute(CARD_ATTRIB_PALMID, getter_Copies(palmIDStr));
-        if(NS_SUCCEEDED(rv) && palmIDStr.get()) {
-            PRInt32 palmID=0;
-            PRFloat64 f = PR_strtod(NS_LossyConvertUTF16toASCII(palmIDStr).get(), nsnull);
-            PRInt64 l;
-            LL_D2L(l, f);
-            LL_L2UI(palmID, l);
-            if(palmID && mRecordId)
-                return mRecordId == palmID;
-        }
+    // first check the palmID for the cards if they exist
+    nsString palmIDStr;
+    rv = card->GetPropertyAsAString(CARD_ATTRIB_PALMID, palmIDStr);
+    if (NS_SUCCEEDED(rv) && palmIDStr.get()) {
+      PRInt32 palmID=0;
+      PRFloat64 f = PR_strtod(NS_LossyConvertUTF16toASCII(palmIDStr).get(), nsnull);
+      PRInt64 l;
+      LL_D2L(l, f);
+      LL_L2UI(palmID, l);
+      if (palmID && mRecordId)
+        return mRecordId == palmID;
     }
 
     nsString str;
     card->GetFirstName(str);
-    if (Compare(str, m_FirstName, nsCaseInsensitiveStringComparator()))
+    if (Compare(str, kFirstNameProperty))
         return PR_FALSE;
     card->GetLastName(str);
-    if (Compare(str, m_LastName, nsCaseInsensitiveStringComparator()))
+    if (Compare(str, kLastNameProperty))
         return PR_FALSE;
     card->GetDisplayName(str);
-    if (Compare(str, m_DisplayName, nsCaseInsensitiveStringComparator()))
+    if (Compare(str, kDisplayNameProperty))
         return PR_FALSE;
-    card->GetNickName(str);
-    if (Compare(str, m_NickName, nsCaseInsensitiveStringComparator()))
+    if (NS_FAILED(card->GetPropertyAsAString(kNicknameProperty, str)))
+      str.Truncate();
+    if (Compare(str, kNicknameProperty))
         return PR_FALSE;
 
     return PR_TRUE;
 }
 
 
-void nsAbIPCCard::CopyValue(PRBool isUnicode, nsString & attribValue, LPTSTR * result)
+void nsAbIPCCard::CopyValue(PRBool isUnicode, const char *attribute, LPTSTR * result)
 {
     *result = NULL;
+    nsAutoString attribValue;
+    GetPropertyAsAString(attribute, attribValue);
     if(attribValue.Length() && attribValue.get()) {
         PRInt32 length;
         if(isUnicode) {                                 
             length = attribValue.Length()+1;
             PRUnichar * Str = (PRUnichar *) CoTaskMemAlloc(sizeof(PRUnichar) * length);
             wcsncpy(Str, attribValue.get(), length-1);
             Str[length-1] = '\0';
             *result = Str;
@@ -842,58 +873,63 @@ nsresult nsAbIPCCard::GetABCOMCardStruct
     // receive a different return code even if nsSynchronizeAB() return S_OK.
     memset(card, 0, sizeof(nsABCOMCardStruct));
     card->dwRecordId = mRecordId;
     card->dwCategoryId = mCategoryId;
     card->dwStatus = mStatus;
     card->addressToUse = CPalmSyncImp::nsUseABHomeAddressForPalmAddress(); // 0 == home, 1 == work
     PR_LOG(PALMSYNC, PR_LOG_DEBUG, ("nsAbIPCCard::GetABCOMCardStruct using %d\n", card->addressToUse));
 
-    CopyValue(isUnicode, m_FirstName, &card->firstName);
-    CopyValue(isUnicode, m_LastName, &card->lastName);
-    CopyValue(isUnicode, m_DisplayName, &card->displayName);
-    CopyValue(isUnicode, m_NickName, &card->nickName);
-    CopyValue(isUnicode, m_PrimaryEmail, &card->primaryEmail);
-    CopyValue(isUnicode, m_SecondEmail, &card->secondEmail);
-    CopyValue(isUnicode, m_WorkPhone, &card->workPhone);
-    CopyValue(isUnicode, m_HomePhone, &card->homePhone);
-    CopyValue(isUnicode, m_FaxNumber, &card->faxNumber);
-    CopyValue(isUnicode, m_PagerNumber, &card->pagerNumber);
-    CopyValue(isUnicode, m_CellularNumber, &card->cellularNumber);
+    CopyValue(isUnicode, kFirstNameProperty, &card->firstName);
+    CopyValue(isUnicode, kLastNameProperty, &card->lastName);
+    CopyValue(isUnicode, kDisplayNameProperty, &card->displayName);
+    CopyValue(isUnicode, kNicknameProperty, &card->nickName);
+    CopyValue(isUnicode, kPriEmailProperty, &card->primaryEmail);
+    CopyValue(isUnicode, k2ndEmailProperty, &card->secondEmail);
+    CopyValue(isUnicode, kWorkPhoneProperty, &card->workPhone);
+    CopyValue(isUnicode, kHomePhoneProperty, &card->homePhone);
+    CopyValue(isUnicode, kFaxProperty, &card->faxNumber);
+    CopyValue(isUnicode, kPagerProperty, &card->pagerNumber);
+    CopyValue(isUnicode, kCellularProperty, &card->cellularNumber);
     // See if home address contains multiple lines.
     JoinHomeAndWorkAddresses(isUnicode, card);
-    CopyValue(isUnicode, m_HomeCity, &card->homeCity);
-    CopyValue(isUnicode, m_HomeState, &card->homeState);
-    CopyValue(isUnicode, m_HomeZipCode, &card->homeZipCode);
-    CopyValue(isUnicode, m_HomeCountry, &card->homeCountry);
-    CopyValue(isUnicode, m_WorkCity, &card->workCity);
-    CopyValue(isUnicode, m_WorkState, &card->workState);
-    CopyValue(isUnicode, m_WorkZipCode, &card->workZipCode);
-    CopyValue(isUnicode, m_WorkCountry, &card->workCountry);
-    CopyValue(isUnicode, m_JobTitle, &card->jobTitle);
-    CopyValue(isUnicode, m_Department, &card->department);
-    CopyValue(isUnicode, m_Company, &card->company);
-    CopyValue(isUnicode, m_WebPage1, &card->webPage1);
-    CopyValue(isUnicode, m_WebPage2, &card->webPage2);
-    CopyValue(isUnicode, m_BirthYear, &card->birthYear);
-    CopyValue(isUnicode, m_BirthMonth, &card->birthMonth);
-    CopyValue(isUnicode, m_BirthDay, &card->birthDay);
-    CopyValue(isUnicode, m_Custom1, &card->custom1);
-    CopyValue(isUnicode, m_Custom2, &card->custom2);
-    CopyValue(isUnicode, m_Custom3, &card->custom3);
-    CopyValue(isUnicode, m_Custom4, &card->custom4);
-    CopyValue(isUnicode, m_Note, &card->notes);
+    CopyValue(isUnicode, kHomeCityProperty, &card->homeCity);
+    CopyValue(isUnicode, kHomeStateProperty, &card->homeState);
+    CopyValue(isUnicode, kHomeZipCodeProperty, &card->homeZipCode);
+    CopyValue(isUnicode, kHomeCountryProperty, &card->homeCountry);
+    CopyValue(isUnicode, kWorkCityProperty, &card->workCity);
+    CopyValue(isUnicode, kWorkStateProperty, &card->workState);
+    CopyValue(isUnicode, kWorkZipCodeProperty, &card->workZipCode);
+    CopyValue(isUnicode, kWorkCountryProperty, &card->workCountry);
+    CopyValue(isUnicode, kJobTitleProperty, &card->jobTitle);
+    CopyValue(isUnicode, kDepartmentProperty, &card->department);
+    CopyValue(isUnicode, kCompanyProperty, &card->company);
+    CopyValue(isUnicode, kWorkWebPageProperty, &card->webPage1);
+    CopyValue(isUnicode, kHomeWebPageProperty, &card->webPage2);
+    CopyValue(isUnicode, kBirthYearProperty, &card->birthYear);
+    CopyValue(isUnicode, kBirthMonthProperty, &card->birthMonth);
+    CopyValue(isUnicode, kBirthDayProperty, &card->birthDay);
+    CopyValue(isUnicode, kCustom1Property, &card->custom1);
+    CopyValue(isUnicode, kCustom2Property, &card->custom2);
+    CopyValue(isUnicode, kCustom3Property, &card->custom3);
+    CopyValue(isUnicode, kCustom4Property, &card->custom4);
+    CopyValue(isUnicode, kNotesProperty, &card->notes);
 
-    card->lastModifiedDate = m_LastModDate;
-    card->preferMailFormat = m_PreferMailFormat;
+    GetPropertyAsUint32(kLastModifiedDateProperty,
+                        (PRUint32*)&card->lastModifiedDate);
+    GetPropertyAsUint32(kPreferMailFormatProperty,
+                        (PRUint32*)&card->preferMailFormat);
     card->addressToUse = CPalmSyncImp::nsUseABHomeAddressForPalmAddress(); // 0 == home, 1 == work
+    nsAutoString homePhone, workPhone;
+    GetPropertyAsAString(kHomePhoneProperty, homePhone);
+    GetPropertyAsAString(kWorkPhoneProperty, workPhone);
     if (CPalmSyncImp::nsPreferABHomePhoneForPalmPhone())
-      card->preferredPhoneNum = (m_HomePhone.IsEmpty()) ? (m_WorkPhone.IsEmpty() ? 4 : 1) : 2;
+      card->preferredPhoneNum = (homePhone.IsEmpty()) ? (workPhone.IsEmpty() ? 4 : 1) : 2;
     else
-      card->preferredPhoneNum = (m_WorkPhone.IsEmpty()) ? 2 : (m_WorkPhone.IsEmpty() ? 4 : 1);
+      card->preferredPhoneNum = (workPhone.IsEmpty()) ? 2 : (workPhone.IsEmpty() ? 4 : 1);
     card->isMailList = m_IsMailList;
     // Can't use ToNewCString() call here becasue MSCOM will complaint about
     // memory deallocation (ie, NdrPointerFree()) use CoTaskMemAlloc() instead.
     if (m_MailListURI.IsEmpty())
       card->mailListURI = NULL;
     else
     {
       PRInt32 length = m_MailListURI.Length()+1;
@@ -966,13 +1002,21 @@ void nsAbIPCCard::JoinAddress(PRBool isU
       strncpy(str, cStr.get(), strLength-1);
       str[strLength-1] = '\0';
     }
     *ptrAddress = (LPTSTR) str;
   } 
 }
 void nsAbIPCCard::JoinHomeAndWorkAddresses(PRBool isUnicode, nsABCOMCardStruct * card)
 {
-  JoinAddress(isUnicode, &card->homeAddress, m_HomeAddress, m_HomeAddress2);
-  JoinAddress(isUnicode, &card->workAddress, m_WorkAddress, m_WorkAddress2);
+  nsAutoString address, address2;
+  GetPropertyAsAString(kHomeAddressProperty, address);
+  GetPropertyAsAString(kHomeAddress2Property, address2);
+  JoinAddress(isUnicode, &card->homeAddress, address, address2);
+
+  address.Truncate();
+  address2.Truncate();
+  GetPropertyAsAString(kWorkAddressProperty, address);
+  GetPropertyAsAString(kWorkAddress2Property, address2);
+  JoinAddress(isUnicode, &card->workAddress, address, address2);
 }
 
 
--- a/mailnews/extensions/palmsync/src/nsAbIPCCard.h
+++ b/mailnews/extensions/palmsync/src/nsAbIPCCard.h
@@ -34,32 +34,31 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsAbIPCCard_h__
 #define nsAbIPCCard_h__
 
-#include "nsAbMDBCard.h"
-#include "nsIAbMDBCard.h"
+#include "nsAbCardProperty.h"
 #include "nsISupportsArray.h"
 #include "nsVoidArray.h"
 #include "IPalmSync.h"
 
 // these are states of Palm record
 // as defined in the Palm CDK
 #define ATTR_DELETED        0x0001
 #define ATTR_ARCHIVED       0x0002
 #define ATTR_MODIFIED       0x0004
 #define ATTR_NEW            0x0008
 #define ATTR_NONE           0x0020
 #define ATTR_NO_REC         0x0040
 
-class nsAbIPCCard : public nsAbMDBCard
+class nsAbIPCCard : public nsAbCardProperty
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     
     // this checks for all card data fields
     NS_IMETHOD Equals(nsIAbCard *card, PRBool *_retval);
     PRBool Equals(nsABCOMCardStruct * card, nsStringArray & differingAttrs);
     PRBool EqualsAfterUnicodeConversion(nsABCOMCardStruct * card, nsStringArray & differingAttrs);
@@ -88,17 +87,18 @@ public:
     void SetCategoryId(PRUint32 catID) { mCategoryId = catID; }
     PRUint32 GetCategoryId() { return mCategoryId; }
 
 private:
     PRUint32 mRecordId;
     PRUint32 mCategoryId;
     PRUint32 mStatus;
 
-    void CopyValue(PRBool isUnicode, nsString & attribValue, LPTSTR * result);
-    PRBool CompareValue(PRBool isUnicode, LPTSTR cardValue, nsString & attribValue);
+    void CopyValue(PRBool isUnicode, const char *attribute, LPTSTR * result);
+    PRBool CompareValue(PRBool isUnicode, LPTSTR cardValue, const char *attribute);
+    PRBool Compare(nsString &cardValue, const char *attribute);
     void SplitHomeAndWorkAddresses(nsABCOMCardStruct * card, PRBool isUnicode);
     void SplitAddresses(PRBool isUnicode, LPTSTR homeAddress, LPTSTR workAddress);
     void JoinHomeAndWorkAddresses(PRBool isUnicode, nsABCOMCardStruct * card);
     void JoinAddress(PRBool isUnicode, LPTSTR *ptrAddress, nsString &address1, nsString &address2);
 };
 
 #endif
--- a/mailnews/extensions/palmsync/src/nsAbPalmSync.cpp
+++ b/mailnews/extensions/palmsync/src/nsAbPalmSync.cpp
@@ -39,17 +39,16 @@
 
 #include "nsRDFResource.h"
 #include "nsAbPalmSync.h"
 #include "nsAbBaseCID.h"
 #include "nsMsgI18N.h"
 #include "nsIRDFService.h"
 #include "nsRDFCID.h"
 #include "nsUnicharUtils.h"
-#include "nsIAbMDBCard.h"
 #include "nsIAbManager.h"
 #include "nsAbCardProperty.h"
 #include "prdtoa.h"
 #include "nsMsgUtils.h"
 #include "nsIArray.h"
 #include "nsArrayUtils.h"
 
 #define  PREVIOUS_EXTENSION ".prev"
@@ -150,26 +149,25 @@ nsAbPalmHotSync::~nsAbPalmHotSync()
     // clear the nsVoidArray, don't free the stored pointers since they are freed by calling app (Conduit)
     mPalmRecords.Clear();
 
     if(mDBOpen && mABDB)
         mABDB->Close(PR_FALSE);
 }
 
 // this is a utility function
-void nsAbPalmHotSync::ConvertAssignPalmIDAttrib(PRUint32 id, nsIAbMDBCard * card)  
+void nsAbPalmHotSync::ConvertAssignPalmIDAttrib(PRUint32 id, nsIAbCard * card)  
 { 
     PRInt64 l;
     LL_UI2L(l, id);
     PRFloat64 f;
     LL_L2F(f, l);
     char buf[128];
     PR_cnvtf(buf, 128, 0, f);
-    card->SetAbDatabase(mABDB);
-    card->SetStringAttribute(CARD_ATTRIB_PALMID,NS_ConvertASCIItoUTF16(buf).get());
+    mABDB->SetCardValue(card, CARD_ATTRIB_PALMID, NS_ConvertASCIItoUTF16(buf).get(), PR_TRUE);
 }
 
 nsresult nsAbPalmHotSync::GetABInterface()
 {
   // Use GetChildNodes() call here.
   nsresult rv;
   nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
   if (NS_FAILED(rv))
@@ -524,17 +522,17 @@ nsresult nsAbPalmHotSync::LoadDeletedCar
             continue;
         
         PRBool isMailingList=PR_FALSE;
         rv = card->GetIsMailList(&isMailingList);
         if (NS_FAILED(rv) || isMailingList)
             continue;
 
         PRUint32 lastModifiedDate = 0;
-        rv = card->GetLastModifiedDate(&lastModifiedDate);
+        rv = card->GetPropertyAsUint32(kLastModifiedDateProperty, &lastModifiedDate);
         if (NS_FAILED(rv) || !lastModifiedDate)
             continue;
 
         if(lastModifiedDate > mPalmSyncTimeStamp)
         {
             nsAbIPCCard  ipcCard(card);
             // check in the list of Palm records
             for(PRInt32 i=mPalmRecords.Count()-1; i >=0;  i--) 
@@ -580,17 +578,17 @@ nsresult nsAbPalmHotSync::LoadNewModifie
             continue;
 
         PRBool isMailingList=PR_FALSE;
         rv = card->GetIsMailList(&isMailingList);
         if (NS_FAILED(rv) || isMailingList) // if mailing list go to cards
             continue;
 
         PRUint32 lastModifiedDate = 0;
-        rv = card->GetLastModifiedDate(&lastModifiedDate);
+        rv = card->GetPropertyAsUint32(kLastModifiedDateProperty, &lastModifiedDate);
         if (NS_FAILED(rv))
             continue;
 
         if(lastModifiedDate > mPalmSyncTimeStamp  // take care of modified
             || !lastModifiedDate || !mPalmSyncTimeStamp) 
         {  // take care of new or never before sync
             
             //create nsAbIPCCard and assign its status based on lastModifiedDate
@@ -820,19 +818,18 @@ nsresult nsAbPalmHotSync::UpdateMozABWit
         {
           rv = mABDB->GetCardFromAttribute(nsnull, CARD_ATTRIB_DISPLAY,
 					   nsDependentCString((const char *) palmRec->displayName),
 					   PR_FALSE, getter_AddRefs(existingCard));
           // if card with this display name exists, just continue; But, we should make sure
           // it's associated with the palm card going forward, so set the palmid.
           if (NS_SUCCEEDED(rv) && existingCard)
           {
-            nsCOMPtr<nsIAbMDBCard> dbCard = do_QueryInterface(existingCard);
-
-            dbCard->SetStringAttribute(CARD_ATTRIB_PALMID, NS_ConvertASCIItoUTF16(recordIDBuf).get());
+            existingCard->SetPropertyAsAUTF8String(CARD_ATTRIB_PALMID,
+                nsDependentCString(recordIDBuf));
             continue;
           }
 
         }
         if(NS_SUCCEEDED(rv) && existingCard) 
         {
             // Archived is the same as deleted in palm.
             if(palmRec->dwStatus & ATTR_DELETED || palmRec->dwStatus & ATTR_ARCHIVED) 
@@ -852,47 +849,40 @@ nsresult nsAbPalmHotSync::UpdateMozABWit
                 {
                     existingCard->Copy(&ipcCard);
                     rv = mABDB->EditCard(existingCard, PR_FALSE, nsnull);
                     continue;
                 }
             }
         }
 
-        nsCOMPtr<nsIAbMDBCard> dbCard;
-        dbCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
+        nsCOMPtr<nsIAbCard> newCard;
+        newCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
         if(NS_FAILED(rv))
             continue;
 
-        nsCOMPtr<nsIAbCard> newCard;
-        newCard = do_QueryInterface(dbCard, &rv);
-        if(NS_FAILED(rv)) 
-            continue;
-
         rv = newCard->Copy(&ipcCard);
         if(NS_FAILED(rv)) 
             continue;
 
         // if the card does not exist
         if((ipcCard.GetStatus() == ATTR_NEW)
             ||(ipcCard.GetStatus() == ATTR_MODIFIED)
             || (ipcCard.GetStatus() == ATTR_NONE)) 
         {
             PRUint32 modTimeInSec;
             PRTime2Seconds(PR_Now(), &modTimeInSec);
-            ipcCard.SetLastModifiedDate(modTimeInSec);
+            ipcCard.SetPropertyAsUint32(kLastModifiedDateProperty, modTimeInSec);
             rv = mABDB->CreateNewCardAndAddToDB(newCard, PR_FALSE, nsnull);
             if(NS_SUCCEEDED(rv)) 
             {
                 // now set the attribute for the PalmRecID in the card in the DB
-                dbCard->SetAbDatabase(mABDB);
-                dbCard->SetStringAttribute(CARD_ATTRIB_PALMID, NS_ConvertASCIItoUTF16(recordIDBuf).get());
-                newCard = do_QueryInterface(dbCard, &rv);
-                if(NS_SUCCEEDED(rv))
-                    rv = mABDB->EditCard(newCard, PR_FALSE, nsnull);
+                newCard->SetPropertyAsAUTF8String(CARD_ATTRIB_PALMID,
+                    nsDependentCString(recordIDBuf));
+                rv = mABDB->EditCard(newCard, PR_FALSE, nsnull);
             }
         }
     }
 
     return rv;
 }
 
 
@@ -902,25 +892,22 @@ nsresult nsAbPalmHotSync::Done(PRBool aS
         return NS_ERROR_NOT_INITIALIZED;
 
     nsresult rv=NS_ERROR_UNEXPECTED;
 
     if(aPalmRecIDListCount == mNewCardCount) 
     {
         for(PRUint32 i=0; i<aPalmRecIDListCount; i++) 
         {
-            nsCOMPtr<nsIAbMDBCard> dbCard;
-            rv = mNewCardsArray->QueryElementAt(i, NS_GET_IID(nsIAbMDBCard), getter_AddRefs(dbCard));
-            if(NS_SUCCEEDED(rv) && dbCard) 
+            nsCOMPtr<nsIAbCard> newCard;
+            rv = mNewCardsArray->QueryElementAt(i, NS_GET_IID(nsIAbCard), getter_AddRefs(newCard));
+            if (NS_SUCCEEDED(rv) && newCard) 
             {
-                ConvertAssignPalmIDAttrib(aPalmRecordIDList[i], dbCard);
-                nsCOMPtr<nsIAbCard> newCard;
-                newCard = do_QueryInterface(dbCard, &rv);
-                if(NS_SUCCEEDED(rv))
-                    mABDB->EditCard(newCard, PR_FALSE, nsnull);
+                ConvertAssignPalmIDAttrib(aPalmRecordIDList[i], newCard);
+                mABDB->EditCard(newCard, PR_FALSE, nsnull);
             }
         }
     }
 
     if(mABDB && mDBOpen) 
     {
         if(aSuccess) 
         {
--- a/mailnews/extensions/palmsync/src/nsAbPalmSync.h
+++ b/mailnews/extensions/palmsync/src/nsAbPalmSync.h
@@ -135,17 +135,17 @@ protected:
 
     // Checks with the corresponding Palm record for any discrepencies
     // if any modification needed, this will return the modified card
     // returns whether card exists (in which case it can be discarded)
     PRBool CardExistsInPalmList(nsAbIPCCard  * aIPCCard);
 
     // utility function
     nsresult AddToListForPalm(nsAbIPCCard & ipcCard);
-    void ConvertAssignPalmIDAttrib(PRUint32 id, nsIAbMDBCard * card);
+    void ConvertAssignPalmIDAttrib(PRUint32 id, nsIAbCard * card);
     nsresult GetABInterface();
     nsresult UpdateABInfo(PRUint32 modTime, PRInt32 categoryId);
     nsresult ModifyAB(const char * ABUrl, const nsString &aAbName,
                       const PRUint32 aModTime, const PRInt32 aCategoryId);
     nsresult NewAB(const nsString& aAbName);
 
 };
 
--- a/mailnews/import/src/nsImportFieldMap.cpp
+++ b/mailnews/import/src/nsImportFieldMap.cpp
@@ -418,121 +418,123 @@ NS_IMETHODIMP nsImportFieldMap::GetField
     break;
   case 1:
     rv = card->GetLastName(value);
     break;
   case 2:
     rv = card->GetDisplayName(value);
     break;
   case 3:
-    rv = card->GetNickName(value);
+    rv = card->GetPropertyAsAString(kNicknameProperty, value);
     break;
   case 4:
     rv = card->GetPrimaryEmail(value);
     break;
   case 5:
-    rv = card->GetSecondEmail(value);
+    rv = card->GetPropertyAsAString(k2ndEmailProperty, value);
     break;
   case 6:
-    rv = card->GetWorkPhone(value);
+    rv = card->GetPropertyAsAString(kWorkPhoneProperty, value);
     break;
   case 7:
-    rv = card->GetHomePhone(value);
+    rv = card->GetPropertyAsAString(kHomePhoneProperty, value);
     break;
   case 8:
-    rv = card->GetFaxNumber(value);
+    rv = card->GetPropertyAsAString(kFaxProperty, value);
     break;
   case 9:
-    rv = card->GetPagerNumber(value);
+    rv = card->GetPropertyAsAString(kPagerProperty, value);
     break;
   case 10:
-    rv = card->GetCellularNumber(value);
+    rv = card->GetPropertyAsAString(kCellularProperty, value);
     break;
   case 11:
-    rv = card->GetHomeAddress(value);
+    rv = card->GetPropertyAsAString(kHomeAddressProperty, value);
     break;
   case 12:
-    rv = card->GetHomeAddress2(value);
+    rv = card->GetPropertyAsAString(kHomeAddress2Property, value);
     break;
   case 13:
-    rv = card->GetHomeCity(value);
+    rv = card->GetPropertyAsAString(kHomeCityProperty, value);
     break;
   case 14:
-    rv = card->GetHomeState(value);
+    rv = card->GetPropertyAsAString(kHomeStateProperty, value);
     break;
   case 15:
-    rv = card->GetHomeZipCode(value);
+    rv = card->GetPropertyAsAString(kHomeZipCodeProperty, value);
     break;
   case 16:
-    rv = card->GetHomeCountry(value);
+    rv = card->GetPropertyAsAString(kHomeCountryProperty, value);
     break;
   case 17:
-    rv = card->GetWorkAddress(value);
+    rv = card->GetPropertyAsAString(kWorkAddressProperty, value);
     break;
   case 18:
-    rv = card->GetWorkAddress2(value);
+    rv = card->GetPropertyAsAString(kWorkAddress2Property, value);
     break;
   case 19:
-    rv = card->GetWorkCity(value);
+    rv = card->GetPropertyAsAString(kWorkCityProperty, value);
     break;
   case 20:
-    rv = card->GetWorkState(value);
+    rv = card->GetPropertyAsAString(kWorkStateProperty, value);
     break;
   case 21:
-    rv = card->GetWorkZipCode(value);
+    rv = card->GetPropertyAsAString(kWorkZipCodeProperty, value);
     break;
   case 22:
-    rv = card->GetWorkCountry(value);
+    rv = card->GetPropertyAsAString(kWorkCountryProperty, value);
     break;
   case 23:
-    rv = card->GetJobTitle(value);
+    rv = card->GetPropertyAsAString(kJobTitleProperty, value);
     break;
   case 24:
-    rv = card->GetDepartment(value);
+    rv = card->GetPropertyAsAString(kDepartmentProperty, value);
     break;
   case 25:
-    rv = card->GetCompany(value);
+    rv = card->GetPropertyAsAString(kCompanyProperty, value);
     break;
   case 26:
-    rv = card->GetWebPage1(value);
+    rv = card->GetPropertyAsAString(kWorkWebPageProperty, value);
     break;
   case 27:
-    rv = card->GetWebPage2(value);
+    rv = card->GetPropertyAsAString(kHomeWebPageProperty, value);
     break;
   case 28:
-    rv = card->GetBirthYear(value);
+    rv = card->GetPropertyAsAString(kBirthYearProperty, value);
     break;
   case 29:
-    rv = card->GetBirthMonth(value);
+    rv = card->GetPropertyAsAString(kBirthMonthProperty, value);
     break;
   case 30:
-    rv = card->GetBirthDay(value);
+    rv = card->GetPropertyAsAString(kBirthDayProperty, value);
     break;
   case 31:
-    rv = card->GetCustom1(value);
+    rv = card->GetPropertyAsAString(kCustom1Property, value);
     break;
   case 32:
-    rv = card->GetCustom2(value);
+    rv = card->GetPropertyAsAString(kCustom2Property, value);
     break;
   case 33:
-    rv = card->GetCustom3(value);
+    rv = card->GetPropertyAsAString(kCustom3Property, value);
     break;
   case 34:
-    rv = card->GetCustom4(value);
+    rv = card->GetPropertyAsAString(kCustom4Property, value);
     break;
   case 35:
-    rv = card->GetNotes(value);
+    rv = card->GetPropertyAsAString(kNotesProperty, value);
     break;
   default:
     /* Get the field description, and add it as an anonymous attr? */
     /* OR WHAT???? */
     {
       rv = NS_ERROR_FAILURE;
     }
   }
+  if (rv == NS_ERROR_NOT_AVAILABLE)
+    value = EmptyString();
 
   *_retval = ToNewUnicode(value);
 
   return rv;
 }
 
 NS_IMETHODIMP nsImportFieldMap::GetFieldValueByDescription(nsIAbCard *card, const PRUnichar *fieldDesc, PRUnichar **_retval)
 {