Bug 1587016 - Convert import code to use new address book provider. r=mkmelin
authorGeoff Lankow <geoff@darktrojan.net>
Sat, 12 Oct 2019 11:26:11 +1300
changeset 36328 6a279db8f7370513cd9853ece3d8cb7ce00b62e0
parent 36327 0618eba9d869570c63b4e9d20f2d0b1911f82051
child 36329 f5a320f3ebce383190418b463937d6b0e4f57a00
push id2511
push userclokep@gmail.com
push dateMon, 21 Oct 2019 20:28:27 +0000
treeherdercomm-beta@67169a456144 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmkmelin
bugs1587016
Bug 1587016 - Convert import code to use new address book provider. r=mkmelin
mailnews/addrbook/public/nsIAbLDIFService.idl
mailnews/addrbook/src/nsAbLDIFService.cpp
mailnews/addrbook/src/nsAbLDIFService.h
mailnews/import/becky/src/nsBeckyAddressBooks.cpp
mailnews/import/outlook/src/nsOutlookImport.cpp
mailnews/import/outlook/src/nsOutlookMail.cpp
mailnews/import/outlook/src/nsOutlookMail.h
mailnews/import/public/nsIImportAddressBooks.idl
mailnews/import/public/nsIImportFieldMap.idl
mailnews/import/src/nsImportAddressBooks.cpp
mailnews/import/src/nsImportAddressBooks.h
mailnews/import/src/nsImportFieldMap.cpp
mailnews/import/src/nsImportFieldMap.h
mailnews/import/test/unit/xpcshell.ini
mailnews/import/text/src/nsTextAddress.cpp
mailnews/import/text/src/nsTextAddress.h
mailnews/import/text/src/nsTextImport.cpp
mailnews/import/vcard/src/nsVCardAddress.cpp
mailnews/import/vcard/src/nsVCardAddress.h
mailnews/import/vcard/src/nsVCardImport.cpp
--- a/mailnews/addrbook/public/nsIAbLDIFService.idl
+++ b/mailnews/addrbook/public/nsIAbLDIFService.idl
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "nsISupports.idl"
 
 interface nsIFile;
-interface nsIAddrDatabase;
+interface nsIAbDirectory;
 
 [scriptable, uuid(7afaa95f-0b1c-4d8a-a65f-bb5073ed6d39)]
 interface nsIAbLDIFService : nsISupports {
 
   /**
    * Determine if a file is likely to be an LDIF file based on field
    * names that commonly appear in LDIF files.
    *
@@ -19,22 +19,25 @@ interface nsIAbLDIFService : nsISupports
    * @return      true if the file appears to be of LDIF type,
    *              false otherwise
    */
   boolean isLDIFFile(in nsIFile aSrc);
 
   /**
    * Imports a file into the specified address book.
    *
-   * @param       aDb             The address book to import addresses into.
+   * @param       aDirectory      The address book to import addresses into.
    *
    * @param       aSrc            The file to import addresses from.
    *
    * @param       aStoreLocAsHome Stores the address as a home rather than work
    *                              address.
    *
    * @param       aProgress       May be null, but if a pointer is supplied,
    *                              then it will be updated regularly with the
    *                              current position of reading from the file.
    *
    */
-  void importLDIFFile(in nsIAddrDatabase aDb, in nsIFile aSrc, in boolean aStoreLocAsHome, inout unsigned long aProgress);
+  void importLDIFFile(in nsIAbDirectory aDirectory,
+                      in nsIFile aSrc,
+                      in boolean aStoreLocAsHome,
+                      inout unsigned long aProgress);
 };
--- a/mailnews/addrbook/src/nsAbLDIFService.cpp
+++ b/mailnews/addrbook/src/nsAbLDIFService.cpp
@@ -1,13 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "nsIAddrDatabase.h"
+#include "nsAbBaseCID.h"
+#include "nsIAbDirectory.h"
+#include "nsIAbCard.h"
 #include "nsString.h"
 #include "nsAbLDIFService.h"
 #include "nsIFile.h"
 #include "nsILineInputStream.h"
 #include "nsIInputStream.h"
 #include "nsNetUtil.h"
 #include "nsISeekableStream.h"
 #include "mdb.h"
@@ -47,22 +49,22 @@ static unsigned char b642nib[0x80] = {
     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
     0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
     0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
     0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
     0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff};
 
-NS_IMETHODIMP nsAbLDIFService::ImportLDIFFile(nsIAddrDatabase *aDb,
+NS_IMETHODIMP nsAbLDIFService::ImportLDIFFile(nsIAbDirectory *aDirectory,
                                               nsIFile *aSrc,
                                               bool aStoreLocAsHome,
                                               uint32_t *aProgress) {
   NS_ENSURE_ARG_POINTER(aSrc);
-  NS_ENSURE_ARG_POINTER(aDb);
+  NS_ENSURE_ARG_POINTER(aDirectory);
 
   mStoreLocAsHome = aStoreLocAsHome;
 
   char buf[1024];
   char *pBuf = &buf[0];
   int32_t startPos = 0;
   uint32_t len = 0;
   nsTArray<int32_t> listPosArray;   // where each list/group starts in ldif file
@@ -79,32 +81,32 @@ NS_IMETHODIMP nsAbLDIFService::ImportLDI
   mLdifLine.Truncate();
 
   while (NS_SUCCEEDED(inputStream->Available(&bytesLeft)) && bytesLeft > 0) {
     if (NS_SUCCEEDED(inputStream->Read(pBuf, sizeof(buf), &len)) && len > 0) {
       startPos = 0;
 
       while (NS_SUCCEEDED(GetLdifStringRecord(buf, len, startPos))) {
         if (mLdifLine.Find("groupOfNames") == -1)
-          AddLdifRowToDatabase(aDb, false);
+          AddLdifRowToDatabase(aDirectory, false);
         else {
           // keep file position for mailing list
           listPosArray.AppendElement(savedStartPos);
           listSizeArray.AppendElement(filePos + startPos - savedStartPos);
           ClearLdifRecordBuffer();
         }
         savedStartPos = filePos + startPos;
       }
       filePos += len;
       if (aProgress) *aProgress = (uint32_t)filePos;
     }
   }
   // last row
   if (!mLdifLine.IsEmpty() && mLdifLine.Find("groupOfNames") == -1)
-    AddLdifRowToDatabase(aDb, false);
+    AddLdifRowToDatabase(aDirectory, false);
 
   // mail Lists
   int32_t i, pos;
   uint32_t size;
   int32_t listTotal = listPosArray.Length();
   char *listBuf;
   ClearLdifRecordBuffer();  // make sure the buffer is clean
 
@@ -120,32 +122,31 @@ NS_IMETHODIMP nsAbLDIFService::ImportLDI
       // Allocate enough space for the lists/groups as the size varies.
       listBuf = (char *)PR_Malloc(size);
       if (!listBuf) continue;
       if (NS_SUCCEEDED(inputStream->Read(listBuf, size, &len)) && len > 0) {
         startPos = 0;
 
         while (NS_SUCCEEDED(GetLdifStringRecord(listBuf, len, startPos))) {
           if (mLdifLine.Find("groupOfNames") != -1) {
-            AddLdifRowToDatabase(aDb, true);
+            AddLdifRowToDatabase(aDirectory, true);
             if (NS_SUCCEEDED(
                     seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, 0)))
               break;
           }
         }
       }
       PR_FREEIF(listBuf);
     }
   }
 
   rv = inputStream->Close();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Finally commit everything to the database and return.
-  return aDb->Commit(nsAddrDBCommitType::kLargeCommit);
+  return rv;
 }
 
 /*
  * str_parse_line - takes a line of the form "type:[:] value" and splits it
  * into components "type" and "value".  if a double colon separates type from
  * value, then value is encoded in base 64, and parse_line un-decodes it
  * (in place) before returning.
  * in LDIF, non-ASCII data is treated as base64 encoded UTF-8
@@ -306,377 +307,394 @@ nsresult nsAbLDIFService::GetLdifStringR
 
   if (((stopPos == len) && (mLFCount > 1)) || (mCRCount > 2 && mLFCount) ||
       (!mLFCount && mCRCount > 1))
     return NS_OK;
 
   return NS_ERROR_FAILURE;
 }
 
-void nsAbLDIFService::AddLdifRowToDatabase(nsIAddrDatabase *aDatabase,
+void nsAbLDIFService::AddLdifRowToDatabase(nsIAbDirectory *aDirectory,
                                            bool bIsList) {
+  if (!aDirectory) {
+    return;
+  }
+
   // If no data to process then reset CR/LF counters and return.
   if (mLdifLine.IsEmpty()) {
     mLFCount = 0;
     mCRCount = 0;
     return;
   }
 
-  nsCOMPtr<nsIMdbRow> newRow;
-  if (aDatabase) {
-    if (bIsList)
-      aDatabase->GetNewListRow(getter_AddRefs(newRow));
-    else
-      aDatabase->GetNewRow(getter_AddRefs(newRow));
-
-    if (!newRow) return;
-  } else
-    return;
+  nsCOMPtr<nsIAbCard> newCard = do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID);
+  nsTArray<nsCString> members;
 
   char *cursor = ToNewCString(mLdifLine);
   char *saveCursor = cursor; /* keep for deleting */
   char *line = 0;
   char *typeSlot = 0;
   char *valueSlot = 0;
   int length = 0;  // the length  of an ldif attribute
   while ((line = str_getline(&cursor)) != nullptr) {
     if (NS_SUCCEEDED(str_parse_line(line, &typeSlot, &valueSlot, &length))) {
-      AddLdifColToDatabase(aDatabase, newRow, typeSlot, valueSlot, bIsList);
+      nsAutoCString colType(typeSlot);
+      nsAutoCString column(valueSlot);
+
+      // 4.x exports attributes like "givenname",
+      // mozilla does "givenName" to be compliant with RFC 2798
+      ToLowerCase(colType);
+
+      if (colType.EqualsLiteral("member") ||
+          colType.EqualsLiteral("uniquemember")) {
+        members.AppendElement(column);
+      } else {
+        AddLdifColToDatabase(aDirectory, newCard, colType, column, bIsList);
+      }
     } else
       continue;  // parse error: continue with next loop iteration
   }
   free(saveCursor);
-  aDatabase->AddCardRowToDB(newRow);
+
+  if (bIsList) {
+    nsCOMPtr<nsIAbDirectory> newList =
+        do_CreateInstance(NS_ABDIRPROPERTY_CONTRACTID);
+    newList->SetIsMailList(true);
+
+    nsAutoString temp;
+    newCard->GetDisplayName(temp);
+    newList->SetDirName(temp);
+    temp.Truncate();
+    newCard->GetPropertyAsAString(kNicknameProperty, temp);
+    newList->SetListNickName(temp);
+    temp.Truncate();
+    newCard->GetPropertyAsAString(kNotesProperty, temp);
+    newList->SetDescription(temp);
+
+    nsIAbDirectory *outList;
+    aDirectory->AddMailList(newList, &outList);
 
-  if (bIsList) aDatabase->AddListDirNode(newRow);
+    int32_t count = members.Length();
+    for (int32_t i = 0; i < count; ++i) {
+      nsAutoCString email;
+      int32_t emailPos = members[i].Find("mail=");
+      emailPos += strlen("mail=");
+      email = Substring(members[i], emailPos);
+
+      nsCOMPtr<nsIAbCard> emailCard;
+      aDirectory->CardForEmailAddress(email, getter_AddRefs(emailCard));
+      if (emailCard) {
+        nsIAbCard *outCard;
+        outList->AddCard(emailCard, &outCard);
+      }
+    }
+  } else {
+    nsIAbCard *outCard;
+    aDirectory->AddCard(newCard, &outCard);
+  }
 
   // Clear buffer for next record
   ClearLdifRecordBuffer();
 }
 
-void nsAbLDIFService::AddLdifColToDatabase(nsIAddrDatabase *aDatabase,
-                                           nsIMdbRow *newRow, char *typeSlot,
-                                           char *valueSlot, bool bIsList) {
-  nsAutoCString colType(typeSlot);
-  nsAutoCString column(valueSlot);
+void nsAbLDIFService::AddLdifColToDatabase(nsIAbDirectory *aDirectory,
+                                           nsIAbCard *newCard,
+                                           nsCString colType, nsCString column,
+                                           bool bIsList) {
+  nsString value = NS_ConvertUTF8toUTF16(column);
 
-  // 4.x exports attributes like "givenname",
-  // mozilla does "givenName" to be compliant with RFC 2798
-  ToLowerCase(colType);
-
-  mdb_u1 firstByte = (mdb_u1)(colType.get())[0];
+  char firstByte = colType.get()[0];
   switch (firstByte) {
     case 'b':
       if (colType.EqualsLiteral("birthyear"))
-        aDatabase->AddBirthYear(newRow, column.get());
+        newCard->SetPropertyAsAString(kBirthYearProperty, value);
       else if (colType.EqualsLiteral("birthmonth"))
-        aDatabase->AddBirthMonth(newRow, column.get());
+        newCard->SetPropertyAsAString(kBirthMonthProperty, value);
       else if (colType.EqualsLiteral("birthday"))
-        aDatabase->AddBirthDay(newRow, column.get());
+        newCard->SetPropertyAsAString(kBirthDayProperty, value);
       break;  // 'b'
 
     case 'c':
       if (colType.EqualsLiteral("cn") || colType.EqualsLiteral("commonname")) {
-        if (bIsList)
-          aDatabase->AddListName(newRow, column.get());
-        else
-          aDatabase->AddDisplayName(newRow, column.get());
+        newCard->SetDisplayName(value);
       } else if (colType.EqualsLiteral("c") ||
                  colType.EqualsLiteral("countryname")) {
         if (mStoreLocAsHome)
-          aDatabase->AddHomeCountry(newRow, column.get());
+          newCard->SetPropertyAsAString(kHomeCountryProperty, value);
         else
-          aDatabase->AddWorkCountry(newRow, column.get());
+          newCard->SetPropertyAsAString(kWorkCountryProperty, value);
       }
 
       else if (colType.EqualsLiteral("cellphone"))
-        aDatabase->AddCellularNumber(newRow, column.get());
+        newCard->SetPropertyAsAString(kCellularProperty, value);
 
       else if (colType.EqualsLiteral("carphone"))
-        aDatabase->AddCellularNumber(newRow, column.get());
+        newCard->SetPropertyAsAString(kCellularProperty, value);
 
       else if (colType.EqualsLiteral("custom1"))
-        aDatabase->AddCustom1(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom1Property, value);
 
       else if (colType.EqualsLiteral("custom2"))
-        aDatabase->AddCustom2(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom2Property, value);
 
       else if (colType.EqualsLiteral("custom3"))
-        aDatabase->AddCustom3(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom3Property, value);
 
       else if (colType.EqualsLiteral("custom4"))
-        aDatabase->AddCustom4(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom4Property, value);
 
       else if (colType.EqualsLiteral("company"))
-        aDatabase->AddCompany(newRow, column.get());
+        newCard->SetPropertyAsAString(kCompanyProperty, value);
       break;  // 'c'
 
     case 'd':
-      if (colType.EqualsLiteral("description")) {
-        if (bIsList)
-          aDatabase->AddListDescription(newRow, column.get());
-        else
-          aDatabase->AddNotes(newRow, column.get());
-      }
+      if (colType.EqualsLiteral("description"))
+        newCard->SetPropertyAsAString(kNotesProperty, value);
 
       else if (colType.EqualsLiteral("department"))
-        aDatabase->AddDepartment(newRow, column.get());
+        newCard->SetPropertyAsAString(kDepartmentProperty, value);
 
-      else if (colType.EqualsLiteral("displayname")) {
-        if (bIsList)
-          aDatabase->AddListName(newRow, column.get());
-        else
-          aDatabase->AddDisplayName(newRow, column.get());
-      }
+      else if (colType.EqualsLiteral("displayname"))
+        newCard->SetDisplayName(value);
       break;  // 'd'
 
     case 'f':
 
       if (colType.EqualsLiteral("fax") ||
           colType.EqualsLiteral("facsimiletelephonenumber"))
-        aDatabase->AddFaxNumber(newRow, column.get());
+        newCard->SetPropertyAsAString(kFaxProperty, value);
       break;  // 'f'
 
     case 'g':
-      if (colType.EqualsLiteral("givenname"))
-        aDatabase->AddFirstName(newRow, column.get());
-
+      if (colType.EqualsLiteral("givenname")) newCard->SetFirstName(value);
       break;  // 'g'
 
     case 'h':
       if (colType.EqualsLiteral("homephone"))
-        aDatabase->AddHomePhone(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomePhoneProperty, value);
 
       else if (colType.EqualsLiteral("homestreet"))
-        aDatabase->AddHomeAddress(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeAddressProperty, value);
 
       else if (colType.EqualsLiteral("homeurl"))
-        aDatabase->AddWebPage2(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeWebPageProperty, value);
       break;  // 'h'
 
     case 'l':
       if (colType.EqualsLiteral("l") || colType.EqualsLiteral("locality")) {
         if (mStoreLocAsHome)
-          aDatabase->AddHomeCity(newRow, column.get());
+          newCard->SetPropertyAsAString(kHomeCityProperty, value);
         else
-          aDatabase->AddWorkCity(newRow, column.get());
+          newCard->SetPropertyAsAString(kWorkCityProperty, value);
       }
       // labeledURI contains a URI and, optionally, a label
       // This will remove the label and place the URI as the work URL
       else if (colType.EqualsLiteral("labeleduri")) {
         int32_t index = column.FindChar(' ');
         if (index != -1) column.SetLength(index);
 
-        aDatabase->AddWebPage1(newRow, column.get());
+        newCard->SetPropertyAsAString(kWorkWebPageProperty,
+                                      NS_ConvertUTF8toUTF16(column));
       }
 
       break;  // 'l'
 
     case 'm':
       if (colType.EqualsLiteral("mail"))
-        aDatabase->AddPrimaryEmail(newRow, column.get());
-
-      else if (colType.EqualsLiteral("member") && bIsList)
-        aDatabase->AddLdifListMember(newRow, column.get());
+        newCard->SetPrimaryEmail(value);
 
       else if (colType.EqualsLiteral("mobile"))
-        aDatabase->AddCellularNumber(newRow, column.get());
+        newCard->SetPropertyAsAString(kCellularProperty, value);
 
       else if (colType.EqualsLiteral("mozilla_aimscreenname"))
-        aDatabase->AddAimScreenName(newRow, column.get());
+        newCard->SetPropertyAsAString(kAIMProperty, value);
 
       else if (colType.EqualsLiteral("mozillacustom1"))
-        aDatabase->AddCustom1(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom1Property, value);
 
       else if (colType.EqualsLiteral("mozillacustom2"))
-        aDatabase->AddCustom2(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom2Property, value);
 
       else if (colType.EqualsLiteral("mozillacustom3"))
-        aDatabase->AddCustom3(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom3Property, value);
 
       else if (colType.EqualsLiteral("mozillacustom4"))
-        aDatabase->AddCustom4(newRow, column.get());
+        newCard->SetPropertyAsAString(kCustom4Property, value);
 
       else if (colType.EqualsLiteral("mozillahomecountryname"))
-        aDatabase->AddHomeCountry(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeCountryProperty, value);
 
       else if (colType.EqualsLiteral("mozillahomelocalityname"))
-        aDatabase->AddHomeCity(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeCityProperty, value);
 
       else if (colType.EqualsLiteral("mozillahomestate"))
-        aDatabase->AddHomeState(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeStateProperty, value);
 
       else if (colType.EqualsLiteral("mozillahomestreet"))
-        aDatabase->AddHomeAddress(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeAddressProperty, value);
 
       else if (colType.EqualsLiteral("mozillahomestreet2"))
-        aDatabase->AddHomeAddress2(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeAddress2Property, value);
 
       else if (colType.EqualsLiteral("mozillahomepostalcode"))
-        aDatabase->AddHomeZipCode(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeZipCodeProperty, value);
 
       else if (colType.EqualsLiteral("mozillahomeurl"))
-        aDatabase->AddWebPage2(newRow, column.get());
+        newCard->SetPropertyAsAString(kHomeWebPageProperty, value);
 
-      else if (colType.EqualsLiteral("mozillanickname")) {
-        if (bIsList)
-          aDatabase->AddListNickName(newRow, column.get());
-        else
-          aDatabase->AddNickName(newRow, column.get());
-      }
+      else if (colType.EqualsLiteral("mozillanickname"))
+        newCard->SetPropertyAsAString(kNicknameProperty, value);
 
       else if (colType.EqualsLiteral("mozillasecondemail"))
-        aDatabase->Add2ndEmail(newRow, column.get());
+        newCard->SetPropertyAsAString(k2ndEmailProperty, value);
 
       else if (colType.EqualsLiteral("mozillausehtmlmail")) {
         ToLowerCase(column);
         if (-1 != column.Find("true"))
-          aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
+          newCard->SetPropertyAsUint32(kPreferMailFormatProperty,
+                                       nsIAbPreferMailFormat::html);
         else if (-1 != column.Find("false"))
-          aDatabase->AddPreferMailFormat(newRow,
-                                         nsIAbPreferMailFormat::plaintext);
+          newCard->SetPropertyAsUint32(kPreferMailFormatProperty,
+                                       nsIAbPreferMailFormat::plaintext);
         else
-          aDatabase->AddPreferMailFormat(newRow,
-                                         nsIAbPreferMailFormat::unknown);
+          newCard->SetPropertyAsUint32(kPreferMailFormatProperty,
+                                       nsIAbPreferMailFormat::unknown);
       }
 
       else if (colType.EqualsLiteral("mozillaworkstreet2"))
-        aDatabase->AddWorkAddress2(newRow, column.get());
+        newCard->SetPropertyAsAString(kWorkAddress2Property, value);
 
       else if (colType.EqualsLiteral("mozillaworkurl"))
-        aDatabase->AddWebPage1(newRow, column.get());
+        newCard->SetPropertyAsAString(kWorkWebPageProperty, value);
 
       break;  // 'm'
 
     case 'n':
       if (colType.EqualsLiteral("notes"))
-        aDatabase->AddNotes(newRow, column.get());
+        newCard->SetPropertyAsAString(kNotesProperty, value);
 
       else if (colType.EqualsLiteral("nscpaimscreenname") ||
                colType.EqualsLiteral("nsaimid"))
-        aDatabase->AddAimScreenName(newRow, column.get());
+        newCard->SetPropertyAsAString(kAIMProperty, value);
 
       break;  // 'n'
 
     case 'o':
       if (colType.EqualsLiteral("objectclass"))
         break;
 
       else if (colType.EqualsLiteral("ou") || colType.EqualsLiteral("orgunit"))
-        aDatabase->AddDepartment(newRow, column.get());
+        newCard->SetPropertyAsAString(kDepartmentProperty, value);
 
       else if (colType.EqualsLiteral("o"))  // organization
-        aDatabase->AddCompany(newRow, column.get());
+        newCard->SetPropertyAsAString(kCompanyProperty, value);
 
       break;  // 'o'
 
     case 'p':
       if (colType.EqualsLiteral("postalcode")) {
         if (mStoreLocAsHome)
-          aDatabase->AddHomeZipCode(newRow, column.get());
+          newCard->SetPropertyAsAString(kHomeZipCodeProperty, value);
         else
-          aDatabase->AddWorkZipCode(newRow, column.get());
+          newCard->SetPropertyAsAString(kWorkZipCodeProperty, value);
       }
 
       else if (colType.EqualsLiteral("postofficebox")) {
         nsAutoCString workAddr1, workAddr2;
         SplitCRLFAddressField(column, workAddr1, workAddr2);
-        aDatabase->AddWorkAddress(newRow, workAddr1.get());
-        aDatabase->AddWorkAddress2(newRow, workAddr2.get());
+        newCard->SetPropertyAsAString(kWorkAddressProperty,
+                                      NS_ConvertUTF8toUTF16(workAddr1));
+        newCard->SetPropertyAsAString(kWorkAddress2Property,
+                                      NS_ConvertUTF8toUTF16(workAddr2));
       } else if (colType.EqualsLiteral("pager") ||
                  colType.EqualsLiteral("pagerphone"))
-        aDatabase->AddPagerNumber(newRow, column.get());
+        newCard->SetPropertyAsAString(kPagerProperty, value);
 
       break;  // 'p'
 
     case 'r':
       if (colType.EqualsLiteral("region")) {
-        aDatabase->AddWorkState(newRow, column.get());
+        newCard->SetPropertyAsAString(kWorkStateProperty, value);
       }
 
       break;  // 'r'
 
     case 's':
       if (colType.EqualsLiteral("sn") || colType.EqualsLiteral("surname"))
-        aDatabase->AddLastName(newRow, column.get());
+        newCard->SetPropertyAsAString(kLastNameProperty, value);
 
       else if (colType.EqualsLiteral("street"))
-        aDatabase->AddWorkAddress(newRow, column.get());
+        newCard->SetPropertyAsAString(kWorkAddressProperty, value);
 
       else if (colType.EqualsLiteral("streetaddress")) {
         nsAutoCString addr1, addr2;
         SplitCRLFAddressField(column, addr1, addr2);
         if (mStoreLocAsHome) {
-          aDatabase->AddHomeAddress(newRow, addr1.get());
-          aDatabase->AddHomeAddress2(newRow, addr2.get());
+          newCard->SetPropertyAsAString(kHomeAddressProperty,
+                                        NS_ConvertUTF8toUTF16(addr1));
+          newCard->SetPropertyAsAString(kHomeAddress2Property,
+                                        NS_ConvertUTF8toUTF16(addr2));
         } else {
-          aDatabase->AddWorkAddress(newRow, addr1.get());
-          aDatabase->AddWorkAddress2(newRow, addr2.get());
+          newCard->SetPropertyAsAString(kWorkAddressProperty,
+                                        NS_ConvertUTF8toUTF16(addr1));
+          newCard->SetPropertyAsAString(kWorkAddress2Property,
+                                        NS_ConvertUTF8toUTF16(addr2));
         }
       } else if (colType.EqualsLiteral("st")) {
         if (mStoreLocAsHome)
-          aDatabase->AddHomeState(newRow, column.get());
+          newCard->SetPropertyAsAString(kHomeStateProperty, value);
         else
-          aDatabase->AddWorkState(newRow, column.get());
+          newCard->SetPropertyAsAString(kWorkStateProperty, value);
       }
 
       break;  // 's'
 
     case 't':
       if (colType.EqualsLiteral("title"))
-        aDatabase->AddJobTitle(newRow, column.get());
+        newCard->SetPropertyAsAString(kJobTitleProperty, value);
 
       else if (colType.EqualsLiteral("telephonenumber")) {
-        aDatabase->AddWorkPhone(newRow, column.get());
+        newCard->SetPropertyAsAString(kWorkPhoneProperty, value);
       }
 
       break;  // 't'
 
-    case 'u':
-
-      if (colType.EqualsLiteral("uniquemember") && bIsList)
-        aDatabase->AddLdifListMember(newRow, column.get());
-
-      break;  // 'u'
-
     case 'w':
       if (colType.EqualsLiteral("workurl"))
-        aDatabase->AddWebPage1(newRow, column.get());
+        newCard->SetPropertyAsAString(kWorkWebPageProperty, value);
 
       break;  // 'w'
 
     case 'x':
       if (colType.EqualsLiteral("xmozillanickname")) {
-        if (bIsList)
-          aDatabase->AddListNickName(newRow, column.get());
-        else
-          aDatabase->AddNickName(newRow, column.get());
+        newCard->SetPropertyAsAString(kNicknameProperty, value);
       }
 
       else if (colType.EqualsLiteral("xmozillausehtmlmail")) {
         ToLowerCase(column);
         if (-1 != column.Find("true"))
-          aDatabase->AddPreferMailFormat(newRow, nsIAbPreferMailFormat::html);
+          newCard->SetPropertyAsUint32(kPreferMailFormatProperty,
+                                       nsIAbPreferMailFormat::html);
         else if (-1 != column.Find("false"))
-          aDatabase->AddPreferMailFormat(newRow,
-                                         nsIAbPreferMailFormat::plaintext);
+          newCard->SetPropertyAsUint32(kPreferMailFormatProperty,
+                                       nsIAbPreferMailFormat::plaintext);
         else
-          aDatabase->AddPreferMailFormat(newRow,
-                                         nsIAbPreferMailFormat::unknown);
+          newCard->SetPropertyAsUint32(kPreferMailFormatProperty,
+                                       nsIAbPreferMailFormat::unknown);
       }
 
       break;  // 'x'
 
     case 'z':
       if (colType.EqualsLiteral("zip"))  // alias for postalcode
       {
         if (mStoreLocAsHome)
-          aDatabase->AddHomeZipCode(newRow, column.get());
+          newCard->SetPropertyAsAString(kHomeZipCodeProperty, value);
         else
-          aDatabase->AddWorkZipCode(newRow, column.get());
+          newCard->SetPropertyAsAString(kWorkZipCodeProperty, value);
       }
 
       break;  // 'z'
 
     default:
       break;  // default
   }
 }
--- a/mailnews/addrbook/src/nsAbLDIFService.h
+++ b/mailnews/addrbook/src/nsAbLDIFService.h
@@ -3,34 +3,32 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef __nsAbLDIFService_h
 #define __nsAbLDIFService_h
 
 #include "nsIAbLDIFService.h"
 #include "nsCOMPtr.h"
 
-class nsIMdbRow;
-
 class nsAbLDIFService : public nsIAbLDIFService {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIABLDIFSERVICE
 
   nsAbLDIFService();
 
  private:
   virtual ~nsAbLDIFService();
   nsresult str_parse_line(char *line, char **type, char **value,
                           int *vlen) const;
   char *str_getline(char **next) const;
   nsresult GetLdifStringRecord(char *buf, int32_t len, int32_t &stopPos);
-  void AddLdifRowToDatabase(nsIAddrDatabase *aDatabase, bool aIsList);
-  void AddLdifColToDatabase(nsIAddrDatabase *aDatabase, nsIMdbRow *newRow,
-                            char *typeSlot, char *valueSlot, bool bIsList);
+  void AddLdifRowToDatabase(nsIAbDirectory *aDirectory, bool aIsList);
+  void AddLdifColToDatabase(nsIAbDirectory *aDirectory, nsIAbCard *newCard,
+                            nsCString colType, nsCString column, bool bIsList);
   void ClearLdifRecordBuffer();
   void SplitCRLFAddressField(nsCString &inputAddress, nsCString &outputLine1,
                              nsCString &outputLine2) const;
 
   bool mStoreLocAsHome;
   nsCString mLdifLine;
   int32_t mLFCount;
   int32_t mCRCount;
--- a/mailnews/import/becky/src/nsBeckyAddressBooks.cpp
+++ b/mailnews/import/becky/src/nsBeckyAddressBooks.cpp
@@ -247,17 +247,17 @@ nsBeckyAddressBooks::FindAddressBooks(ns
 
 NS_IMETHODIMP
 nsBeckyAddressBooks::InitFieldMap(nsIImportFieldMap *aFieldMap) {
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsBeckyAddressBooks::ImportAddressBook(
-    nsIImportABDescriptor *aSource, nsIAddrDatabase *aDestination,
+    nsIImportABDescriptor *aSource, nsIAbDirectory *aDestination,
     nsIImportFieldMap *aFieldMap, nsISupports *aSupportService,
     char16_t **aErrorLog, char16_t **aSuccessLog, bool *aFatalError) {
   NS_ENSURE_ARG_POINTER(aSource);
   NS_ENSURE_ARG_POINTER(aDestination);
   NS_ENSURE_ARG_POINTER(aErrorLog);
   NS_ENSURE_ARG_POINTER(aSuccessLog);
   NS_ENSURE_ARG_POINTER(aFatalError);
 
--- a/mailnews/import/outlook/src/nsOutlookImport.cpp
+++ b/mailnews/import/outlook/src/nsOutlookImport.cpp
@@ -15,17 +15,17 @@
 #include "nsIImportMail.h"
 #include "nsIImportMailboxDescriptor.h"
 #include "nsIImportGeneric.h"
 #include "nsIImportAddressBooks.h"
 #include "nsIImportABDescriptor.h"
 #include "nsIImportFieldMap.h"
 #include "nsXPCOM.h"
 #include "nsISupportsPrimitives.h"
-#include "nsIAddrDatabase.h"
+#include "nsIAbDirectory.h"
 #include "nsOutlookSettings.h"
 #include "nsTextFormatter.h"
 #include "nsOutlookStringBundle.h"
 #include "ImportDebug.h"
 #include "nsUnicharUtils.h"
 
 #include "nsOutlookMail.h"
 
@@ -103,17 +103,17 @@ class ImportOutlookAddressImpl : public 
 
   NS_IMETHOD FindAddressBooks(nsIFile *location, nsIArray **_retval);
 
   NS_IMETHOD InitFieldMap(nsIImportFieldMap *fieldMap) {
     return NS_ERROR_FAILURE;
   }
 
   NS_IMETHOD ImportAddressBook(nsIImportABDescriptor *source,
-                               nsIAddrDatabase *destination,
+                               nsIAbDirectory *destination,
                                nsIImportFieldMap *fieldMap,
                                nsISupports *aSupportService,
                                char16_t **errorLog, char16_t **successLog,
                                bool *fatalError);
 
   NS_IMETHOD GetImportProgress(uint32_t *_retval);
 
   NS_IMETHOD GetSampleData(int32_t index, bool *pFound, char16_t **pStr) {
@@ -444,17 +444,17 @@ NS_IMETHODIMP ImportOutlookAddressImpl::
                                                          nsIArray **_retval) {
   NS_ASSERTION(_retval != nullptr, "null ptr");
   if (!_retval) return NS_ERROR_NULL_POINTER;
 
   return m_address.GetAddressBooks(_retval);
 }
 
 NS_IMETHODIMP ImportOutlookAddressImpl::ImportAddressBook(
-    nsIImportABDescriptor *source, nsIAddrDatabase *destination,
+    nsIImportABDescriptor *source, nsIAbDirectory *destination,
     nsIImportFieldMap *fieldMap, nsISupports *aSupportService,
     char16_t **pErrorLog, char16_t **pSuccessLog, bool *fatalError) {
   m_msgCount = 0;
   m_msgTotal = 0;
   NS_ASSERTION(source != nullptr, "null ptr");
   NS_ASSERTION(destination != nullptr, "null ptr");
   NS_ASSERTION(fatalError != nullptr, "null ptr");
 
@@ -485,17 +485,17 @@ NS_IMETHODIMP ImportOutlookAddressImpl::
   if (NS_SUCCEEDED(rv) && error.IsEmpty())
     ReportSuccess(name, &success);
   else
     ImportOutlookMailImpl::ReportError(OUTLOOKIMPORT_ADDRESS_CONVERTERROR, name,
                                        &error);
 
   ImportOutlookMailImpl::SetLogs(success, error, pErrorLog, pSuccessLog);
   IMPORT_LOG0("*** Returning from outlook address import\n");
-  return destination->Commit(nsAddrDBCommitType::kLargeCommit);
+  return NS_OK;
 }
 
 NS_IMETHODIMP ImportOutlookAddressImpl::GetImportProgress(uint32_t *_retval) {
   NS_ASSERTION(_retval != nullptr, "null ptr");
   if (!_retval) return NS_ERROR_NULL_POINTER;
 
   uint32_t result = m_msgCount;
   if (m_msgTotal) {
--- a/mailnews/import/outlook/src/nsOutlookMail.cpp
+++ b/mailnews/import/outlook/src/nsOutlookMail.cpp
@@ -490,17 +490,17 @@ BOOL nsOutlookMail::WriteData(nsIOutputS
                               int32_t len) {
   uint32_t written;
   nsresult rv = pDest->Write(pData, len, &written);
   return NS_SUCCEEDED(rv) && written == len;
 }
 
 nsresult nsOutlookMail::ImportAddresses(uint32_t *pCount, uint32_t *pTotal,
                                         const char16_t *pName, uint32_t id,
-                                        nsIAddrDatabase *pDb,
+                                        nsIAbDirectory *pDirectory,
                                         nsString &errors) {
   if (id >= (uint32_t)(m_addressList.GetSize())) {
     IMPORT_LOG0("*** Bad address identifier, unable to import\n");
     return NS_ERROR_FAILURE;
   }
 
   uint32_t dummyCount = 0;
   if (pCount)
@@ -578,58 +578,55 @@ nsresult nsOutlookMail::ImportAddresses(
         type.Truncate();
         m_mapi.GetStringFromProp(pVal, type);
         if (type.EqualsLiteral("IPM.Contact")) {
           // This is a contact, add it to the address book!
           subject.Truncate();
           pVal = m_mapi.GetMapiProperty(lpMsg, PR_SUBJECT);
           if (pVal) m_mapi.GetStringFromProp(pVal, subject);
 
-          nsIMdbRow *newRow = nullptr;
-          pDb->GetNewRow(&newRow);
-          // FIXME: Check with Candice about releasing the newRow if it
-          // isn't added to the database.  Candice's code in nsAddressBook
-          // never releases it but that doesn't seem right to me!
-          if (newRow) {
-            if (BuildCard(subject.get(), pDb, newRow, lpMsg, pFieldMap)) {
-              pDb->AddCardRowToDB(newRow);
+          nsCOMPtr<nsIAbCard> newCard =
+              do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID, &rv);
+          if (newCard) {
+            if (BuildCard(subject.get(), pDirectory, newCard, lpMsg,
+                          pFieldMap)) {
+              nsIAbCard *outCard;
+              pDirectory->AddCard(newCard, &outCard);
             }
           }
         } else if (type.EqualsLiteral("IPM.DistList")) {
           // This is a list/group, add it to the address book!
           subject.Truncate();
           pVal = m_mapi.GetMapiProperty(lpMsg, PR_SUBJECT);
           if (pVal) m_mapi.GetStringFromProp(pVal, subject);
-          CreateList(subject.get(), pDb, lpMsg, pFieldMap);
+          CreateList(subject, pDirectory, lpMsg, pFieldMap);
         }
       }
 
       lpMsg->Release();
     }
   }
 
-  rv = pDb->Commit(nsAddrDBCommitType::kLargeCommit);
   return rv;
 }
-nsresult nsOutlookMail::CreateList(const char16_t *pName, nsIAddrDatabase *pDb,
+nsresult nsOutlookMail::CreateList(const nsString &pName,
+                                   nsIAbDirectory *pDirectory,
                                    LPMAPIPROP pUserList,
                                    nsIImportFieldMap *pFieldMap) {
   // If no name provided then we're done.
-  if (!pName || !(*pName)) return NS_OK;
+  if (pName.IsEmpty()) return NS_OK;
 
   nsresult rv = NS_ERROR_FAILURE;
   // Make sure we have db to work with.
-  if (!pDb) return rv;
+  if (!pDirectory) return rv;
 
-  nsCOMPtr<nsIMdbRow> newListRow;
-  rv = pDb->GetNewListRow(getter_AddRefs(newListRow));
+  nsCOMPtr<nsIAbDirectory> newList =
+      do_CreateInstance(NS_ABDIRPROPERTY_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
-  nsAutoCString column;
-  LossyCopyUTF16toASCII(nsDependentString(pName), column);
-  rv = pDb->AddListName(newListRow, column.get());
+  rv = newList->SetDirName(pName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   HRESULT hr;
   LPSPropValue value = NULL;
   ULONG valueCount = 0;
 
   LPSPropTagArray properties = NULL;
   m_mapi.MAPIAllocateBuffer(CbNewSPropTagArray(1), (void **)&properties);
@@ -657,57 +654,38 @@ nsresult nsOutlookMail::CreateList(const
   ULONG total;
 
   total = sa->cValues;
   for (idx = 0; idx < total; idx++) {
     lpEid = (LPENTRYID)sa->lpbin[idx].lpb;
     cbEid = sa->lpbin[idx].cb;
 
     if (!m_mapi.OpenEntry(cbEid, lpEid, (LPUNKNOWN *)&lpMsg)) {
-      IMPORT_LOG1("*** Error opening messages in mailbox: %S\n", pName);
+      IMPORT_LOG1("*** Error opening messages in mailbox: %S\n", pName.get());
       m_mapi.MAPIFreeBuffer(value);
       return NS_ERROR_FAILURE;
     }
     // This is a contact, add it to the address book!
     subject.Truncate();
     pVal = m_mapi.GetMapiProperty(lpMsg, PR_SUBJECT);
     if (pVal) m_mapi.GetStringFromProp(pVal, subject);
 
-    nsCOMPtr<nsIMdbRow> newRow;
-    nsCOMPtr<nsIMdbRow> oldRow;
-    pDb->GetNewRow(getter_AddRefs(newRow));
-    if (newRow) {
-      if (BuildCard(subject.get(), pDb, newRow, lpMsg, pFieldMap)) {
-        nsCOMPtr<nsIAbCard> userCard;
-        nsCOMPtr<nsIAbCard> newCard;
-        userCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv);
-        NS_ENSURE_SUCCESS(rv, rv);
-        pDb->InitCardFromRow(userCard, newRow);
-
-        // add card to db
-        pDb->FindRowByCard(userCard, getter_AddRefs(oldRow));
-        if (oldRow)
-          newRow = oldRow;
-        else
-          pDb->AddCardRowToDB(newRow);
-
-        // add card list
-        pDb->AddListCardColumnsToRow(userCard, newListRow, idx + 1,
-                                     getter_AddRefs(newCard), true, nullptr,
-                                     nullptr);
+    nsCOMPtr<nsIAbCard> newCard =
+        do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID, &rv);
+    if (newCard) {
+      if (BuildCard(subject.get(), pDirectory, newCard, lpMsg, pFieldMap)) {
+        nsIAbCard *outCard;
+        newList->AddCard(newCard, &outCard);
       }
     }
   }
   m_mapi.MAPIFreeBuffer(value);
 
-  rv = pDb->AddCardRowToDB(newListRow);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = pDb->SetListAddressTotal(newListRow, (uint32_t)total);
-  rv = pDb->AddListDirNode(newListRow);
+  nsIAbDirectory *outList;
+  rv = pDirectory->AddMailList(newList, &outList);
   return rv;
 }
 
 void nsOutlookMail::SanitizeValue(nsString &val) {
   MsgReplaceSubstring(val, NS_LITERAL_STRING("\r\n"), NS_LITERAL_STRING(", "));
   MsgReplaceChar(val, "\r\n", ',');
 }
 
@@ -722,18 +700,18 @@ void nsOutlookMail::SplitString(nsString
   if (idx == -1) idx = val1.RFindChar(10);
   if (idx != -1) {
     val2 = Substring(val1, idx + cnt);
     val1.SetLength(idx);
     SanitizeValue(val1);
   }
 }
 
-bool nsOutlookMail::BuildCard(const char16_t *pName, nsIAddrDatabase *pDb,
-                              nsIMdbRow *newRow, LPMAPIPROP pUser,
+bool nsOutlookMail::BuildCard(const char16_t *pName, nsIAbDirectory *pDirectory,
+                              nsIAbCard *newCard, LPMAPIPROP pUser,
                               nsIImportFieldMap *pFieldMap) {
   nsString lastName;
   nsString firstName;
   nsString eMail;
   nsString nickName;
   nsString middleName;
   nsString secondEMail;
   ULONG emailTag;
@@ -804,62 +782,62 @@ bool nsOutlookMail::BuildCard(const char
         displayName.Append(lastName);
       }
     }
   }
 
   // We now have the required fields
   // write them out followed by any optional fields!
   if (!displayName.IsEmpty()) {
-    pDb->AddDisplayName(newRow, NS_ConvertUTF16toUTF8(displayName).get());
+    newCard->SetDisplayName(displayName);
   }
   if (!firstName.IsEmpty()) {
-    pDb->AddFirstName(newRow, NS_ConvertUTF16toUTF8(firstName).get());
+    newCard->SetFirstName(firstName);
   }
   if (!lastName.IsEmpty()) {
-    pDb->AddLastName(newRow, NS_ConvertUTF16toUTF8(lastName).get());
+    newCard->SetLastName(lastName);
   }
   if (!nickName.IsEmpty()) {
-    pDb->AddNickName(newRow, NS_ConvertUTF16toUTF8(nickName).get());
+    newCard->SetPropertyAsAString(kNicknameProperty, nickName);
   }
   if (!eMail.IsEmpty()) {
-    pDb->AddPrimaryEmail(newRow, NS_ConvertUTF16toUTF8(eMail).get());
+    newCard->SetPrimaryEmail(eMail);
   }
   if (!secondEMail.IsEmpty()) {
-    pDb->Add2ndEmail(newRow, NS_ConvertUTF16toUTF8(secondEMail).get());
+    newCard->SetPropertyAsAString(k2ndEmailProperty, secondEMail);
   }
 
   // Do all of the extra fields!
 
   nsString value;
   nsString line2;
 
   if (pFieldMap) {
     int max = sizeof(gMapiFields) / sizeof(MAPIFields);
     for (int i = 0; i < max; i++) {
       pProp = m_mapi.GetMapiProperty(pUser, gMapiFields[i].mapiTag);
       if (pProp) {
         m_mapi.GetStringFromProp(pProp, value);
         if (!value.IsEmpty()) {
           if (gMapiFields[i].multiLine == kNoMultiLine) {
             SanitizeValue(value);
-            pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].mozField,
-                                     value.get());
+            pFieldMap->SetFieldValue(pDirectory, newCard,
+                                     gMapiFields[i].mozField, value);
           } else if (gMapiFields[i].multiLine == kIsMultiLine) {
-            pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].mozField,
-                                     value.get());
+            pFieldMap->SetFieldValue(pDirectory, newCard,
+                                     gMapiFields[i].mozField, value);
           } else {
             line2.Truncate();
             SplitString(value, line2);
             if (!value.IsEmpty())
-              pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].mozField,
-                                       value.get());
+              pFieldMap->SetFieldValue(pDirectory, newCard,
+                                       gMapiFields[i].mozField, value);
             if (!line2.IsEmpty())
-              pFieldMap->SetFieldValue(pDb, newRow, gMapiFields[i].multiLine,
-                                       line2.get());
+              pFieldMap->SetFieldValue(pDirectory, newCard,
+                                       gMapiFields[i].multiLine, line2);
           }
         }
       }
     }
   }
 
   return true;
 }
--- a/mailnews/import/outlook/src/nsOutlookMail.h
+++ b/mailnews/import/outlook/src/nsOutlookMail.h
@@ -7,46 +7,46 @@
 #define nsOutlookMail_h___
 
 #include "nsIArray.h"
 #include "nsString.h"
 #include "nsOutlookCompose.h"
 #include "nsIFile.h"
 #include "MapiApi.h"
 #include "MapiMessage.h"
-#include "nsIAddrDatabase.h"
+#include "nsIAbDirectory.h"
 #include "nsThreadUtils.h"
 
-class nsIAddrDatabase;
 class nsIImportFieldMap;
 
 class nsOutlookMail {
  public:
   nsOutlookMail();
   ~nsOutlookMail();
 
   nsresult GetMailFolders(nsIArray **pArray);
   nsresult GetAddressBooks(nsIArray **pArray);
   nsresult ImportMailbox(uint32_t *pDoneSoFar, bool *pAbort, int32_t index,
                          const char16_t *pName, nsIMsgFolder *pDest,
                          int32_t *pMsgCount);
   nsresult ImportAddresses(uint32_t *pCount, uint32_t *pTotal,
                            const char16_t *pName, uint32_t id,
-                           nsIAddrDatabase *pDb, nsString &errors);
+                           nsIAbDirectory *pDirectory, nsString &errors);
   void OpenMessageStore(CMapiFolder *pNextFolder);
   static BOOL WriteData(nsIOutputStream *pDest, const char *pData, int32_t len);
 
  private:
   bool IsAddressBookNameUnique(nsString &name, nsString &list);
   void MakeAddressBookNameUnique(nsString &name, nsString &list);
   void SanitizeValue(nsString &val);
   void SplitString(nsString &val1, nsString &val2);
-  bool BuildCard(const char16_t *pName, nsIAddrDatabase *pDb, nsIMdbRow *newRow,
-                 LPMAPIPROP pUser, nsIImportFieldMap *pFieldMap);
-  nsresult CreateList(const char16_t *pName, nsIAddrDatabase *pDb,
+  bool BuildCard(const char16_t *pName, nsIAbDirectory *pDirectory,
+                 nsIAbCard *newCard, LPMAPIPROP pUser,
+                 nsIImportFieldMap *pFieldMap);
+  nsresult CreateList(const nsString &pName, nsIAbDirectory *pDirectory,
                       LPMAPIPROP pUserList, nsIImportFieldMap *pFieldMap);
 
  private:
   bool m_gotFolders;
   bool m_gotAddresses;
   bool m_haveMapi;
   CMapiFolderList m_addressList;
   CMapiFolderList m_storeList;
--- a/mailnews/import/public/nsIImportAddressBooks.idl
+++ b/mailnews/import/public/nsIImportAddressBooks.idl
@@ -30,17 +30,17 @@
   4) All done, maybe a what was done panel??
 */
 
 #include "nsISupports.idl"
 
 interface nsIFile;
 interface nsIArray;
 interface nsIImportABDescriptor;
-interface nsIAddrDatabase;
+interface nsIAbDirectory;
 interface nsIImportFieldMap;
 
 [scriptable, uuid(6bba48be-331c-41e3-bc9f-c2ea3754d977)]
 interface nsIImportAddressBooks : nsISupports
 {
   /*
     Does this interface supports 1 or 1..n address books.  You only
     get to choose 1 location so for formats where 1..n address books
@@ -103,17 +103,17 @@ interface nsIImportAddressBooks : nsISup
    *                        acceptable if it is not required), may be required
    *                        for certain import types (e.g. nsIAbLDIFService for
    *                        LDIF import).
    * @param aErrorLog       The error log from the import.
    * @param aSuccessLog     The success log from the import.
    * @param aFatalError     True if there was a fatal error doing the import.
    */
   void ImportAddressBook(in nsIImportABDescriptor aSource,
-                         in nsIAddrDatabase aDestination,
+                         in nsIAbDirectory aDestination,
                          in nsIImportFieldMap aFieldMap,
                          in nsISupports aSupportService,
                          out wstring aErrorLog,
                          out wstring aSuccessLog,
                          out boolean aFatalError);
 
   /*
     Return the amount of the address book that has been imported so far.  This number
--- a/mailnews/import/public/nsIImportFieldMap.idl
+++ b/mailnews/import/public/nsIImportFieldMap.idl
@@ -10,21 +10,18 @@
   The field map is used by import to map fields from the import format
   to mozilla fields.
   For export, the map contains the ordered list of mozilla fields to
   export!
 */
 
 #include "nsISupports.idl"
 
-interface nsIAddrDatabase;
-[ptr] native nsIMdbRow (nsIMdbRow);
-%{C++
-class nsIMdbRow;
-%}
+interface nsIAbCard;
+interface nsIAbDirectory;
 
 [scriptable, uuid(deee9264-1fe3-47b1-b745-47b22de454e2)]
 interface nsIImportFieldMap : nsISupports
 {
   /*
     Flag to indicate whether or not to skip the first record,
     for instance csv files often have field names as the first
     record
@@ -65,10 +62,10 @@ interface nsIImportFieldMap : nsISupport
   /*
     Set the active state of this field
   */
   void SetFieldActive(in long index, in boolean active);
 
   /*
     Set the value of the given field in the database row
   */
-  void SetFieldValue(in nsIAddrDatabase database, in nsIMdbRow row, in long fieldNum, in wstring value);
+  void SetFieldValue(in nsIAbDirectory database, in nsIAbCard row, in long fieldNum, in AString value);
 };
--- a/mailnews/import/src/nsImportAddressBooks.cpp
+++ b/mailnews/import/src/nsImportAddressBooks.cpp
@@ -10,18 +10,18 @@
 #include "nsISupportsPrimitives.h"
 #include "nsIImportABDescriptor.h"
 #include "nsIAbManager.h"
 #include "nsAbBaseCID.h"
 #include "nsImportStringBundle.h"
 #include "nsTextFormatter.h"
 #include "msgCore.h"
 #include "ImportDebug.h"
-#include "nsIAbMDBDirectory.h"
 #include "nsArrayUtils.h"
+#include "nsDirPrefs.h"
 
 nsresult NS_NewGenericAddressBooks(nsIImportGeneric **aImportGeneric) {
   NS_ASSERTION(aImportGeneric != nullptr, "null ptr");
   if (!aImportGeneric) return NS_ERROR_NULL_POINTER;
 
   RefPtr<nsImportGenericAddressBooks> pGen = new nsImportGenericAddressBooks();
   return pGen->QueryInterface(NS_GET_IID(nsIImportGeneric),
                               (void **)aImportGeneric);
@@ -315,110 +315,52 @@ void nsImportGenericAddressBooks::SetLog
   }
   if (pError) {
     pError->GetData(str);
     str.Append(error);
     pError->SetData(error);
   }
 }
 
-already_AddRefed<nsIAddrDatabase> GetAddressBookFromUri(const char *pUri) {
+already_AddRefed<nsIAbDirectory> GetAddressBookFromUri(const char *pUri) {
   if (!pUri) return nullptr;
 
   nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID);
   if (!abManager) return nullptr;
 
   nsCOMPtr<nsIAbDirectory> directory;
   abManager->GetDirectory(nsDependentCString(pUri), getter_AddRefs(directory));
   if (!directory) return nullptr;
 
-  nsCOMPtr<nsIAbMDBDirectory> mdbDirectory = do_QueryInterface(directory);
-  if (!mdbDirectory) return nullptr;
-
-  nsCOMPtr<nsIAddrDatabase> pDatabase;
-  mdbDirectory->GetDatabase(getter_AddRefs(pDatabase));
-  return pDatabase.forget();
+  return directory.forget();
 }
 
-already_AddRefed<nsIAddrDatabase> GetAddressBook(const char16_t *name,
-                                                 bool makeNew) {
+already_AddRefed<nsIAbDirectory> GetAddressBook(nsString name, bool makeNew) {
   if (!makeNew) {
     // FIXME: How do I get the list of address books and look for a
     // specific name.  Major bogosity!
     // For now, assume we didn't find anything with that name
   }
 
   IMPORT_LOG0("In GetAddressBook\n");
 
   nsresult rv;
-  nsCOMPtr<nsIAddrDatabase> pDatabase;
-  nsCOMPtr<nsIFile> dbPath;
+  nsCOMPtr<nsIAbDirectory> directory;
   nsCOMPtr<nsIAbManager> abManager =
       do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
   if (NS_SUCCEEDED(rv)) {
-    /* Get the profile directory */
-    rv = abManager->GetUserProfileDirectory(getter_AddRefs(dbPath));
+    nsAutoCString dirPrefId;
+    rv = abManager->NewAddressBook(name, EmptyCString(), JSDirectory,
+                                   EmptyCString(), dirPrefId);
     if (NS_SUCCEEDED(rv)) {
-      // Create a new address book file - we don't care what the file
-      // name is, as long as it's unique
-      rv = dbPath->Append(NS_LITERAL_STRING("impab.mab"));
-      if (NS_SUCCEEDED(rv)) {
-        rv = dbPath->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
-
-        if (NS_SUCCEEDED(rv)) {
-          IMPORT_LOG0("Getting the address database factory\n");
-
-          nsCOMPtr<nsIAddrDatabase> addrDBFactory =
-              do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
-          if (NS_FAILED(rv)) return nullptr;
-
-          IMPORT_LOG0("Opening the new address book\n");
-          rv = addrDBFactory->Open(dbPath, true, true,
-                                   getter_AddRefs(pDatabase));
-        }
-      }
+      rv = abManager->GetDirectoryFromId(dirPrefId, getter_AddRefs(directory));
     }
   }
-  if (NS_FAILED(rv)) {
-    IMPORT_LOG0(
-        "Failed to get the user profile directory from the address book "
-        "session\n");
-  }
 
-  if (pDatabase && dbPath) {
-    // We made a database, add it to the UI?!?!?!?!?!?!
-    // This is major bogosity again!  Why doesn't the address book
-    // just handle this properly for me?  Uggggg...
-
-    nsCOMPtr<nsIAbDirectory> parentDir;
-    abManager->GetDirectory(NS_LITERAL_CSTRING(kAllDirectoryRoot),
-                            getter_AddRefs(parentDir));
-    if (parentDir) {
-      nsAutoCString URI("moz-abmdbdirectory://");
-      nsAutoCString leafName;
-      rv = dbPath->GetNativeLeafName(leafName);
-      if (NS_FAILED(rv))
-        IMPORT_LOG0("*** Error: Unable to get name of database file\n");
-      else {
-        URI.Append(leafName);
-        rv = parentDir->CreateDirectoryByURI(nsDependentString(name), URI);
-        if (NS_FAILED(rv))
-          IMPORT_LOG0("*** Error: Unable to create address book directory\n");
-      }
-    }
-
-    if (NS_SUCCEEDED(rv))
-      IMPORT_LOG0("Added new address book to the UI\n");
-    else
-      IMPORT_LOG0(
-          "*** Error: An error occurred while adding the address book to the "
-          "UI\n");
-  }
-
-  return pDatabase.forget();
+  return directory.forget();
 }
 
 NS_IMETHODIMP nsImportGenericAddressBooks::BeginImport(
     nsISupportsString *successLog, nsISupportsString *errorLog, bool *_retval) {
   NS_ASSERTION(_retval != nullptr, "null ptr");
   if (!_retval) return NS_ERROR_NULL_POINTER;
 
   nsString success;
@@ -465,24 +407,24 @@ NS_IMETHODIMP nsImportGenericAddressBook
   m_pThreadData->successLog = m_pSuccessLog;
   m_pThreadData->pDestinationUri = m_pDestinationUri;
 
   uint32_t count = 0;
   m_Books->GetLength(&count);
   // Create/obtain any address books that we need here, so that we don't need
   // to do so inside the import thread which would just proxy the create
   // operations back to the main thread anyway.
-  nsCOMPtr<nsIAddrDatabase> db = GetAddressBookFromUri(m_pDestinationUri.get());
+  nsCOMPtr<nsIAbDirectory> db = GetAddressBookFromUri(m_pDestinationUri.get());
   for (uint32_t i = 0; i < count; ++i) {
     nsCOMPtr<nsIImportABDescriptor> book = do_QueryElementAt(m_Books, i);
     if (book) {
       if (!db) {
         nsString name;
         book->GetPreferredName(name);
-        db = GetAddressBook(name.get(), true);
+        db = GetAddressBook(name, true);
       }
       m_DBs.AppendObject(db);
     }
   }
   m_pThreadData->dBs = &m_DBs;
 
   m_pThreadData->stringBundle = m_stringBundle;
 
@@ -596,17 +538,17 @@ static void ImportAddressThread(void *st
       size = 0;
       nsresult rv = book->GetImport(&import);
       if (NS_SUCCEEDED(rv) && import) rv = book->GetSize(&size);
 
       if (NS_SUCCEEDED(rv) && size && import) {
         nsString name;
         book->GetPreferredName(name);
 
-        nsCOMPtr<nsIAddrDatabase> db = pData->dBs->ObjectAt(i);
+        nsCOMPtr<nsIAbDirectory> db = pData->dBs->ObjectAt(i);
 
         bool fatalError = false;
         pData->currentSize = size;
         if (db) {
           char16_t *pSuccess = nullptr;
           char16_t *pError = nullptr;
 
           /*
@@ -639,18 +581,16 @@ static void ImportAddressThread(void *st
         } else {
           nsImportGenericAddressBooks::ReportError(name.get(), &error,
                                                    pData->stringBundle);
         }
 
         pData->currentSize = 0;
         pData->currentTotal += size;
 
-        if (db) db->Close(true);
-
         if (fatalError) {
           pData->fatalError = true;
           break;
         }
       }
     }
   }
 
--- a/mailnews/import/src/nsImportAddressBooks.h
+++ b/mailnews/import/src/nsImportAddressBooks.h
@@ -4,17 +4,17 @@
  * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCOMPtr.h"
 #include "nsIImportAddressBooks.h"
 #include "nsIImportGeneric.h"
 #include "nsIImportFieldMap.h"
 #include "nsString.h"
 #include "nsIFile.h"
-#include "nsIAddrDatabase.h"
+#include "nsIAbDirectory.h"
 #include "nsIAbLDIFService.h"
 #include "nsIStringBundle.h"
 #include "nsIArray.h"
 #include "nsCOMArray.h"
 
 static void ImportAddressThread(void *stuff);
 
 class AddressThreadData;
@@ -36,17 +36,17 @@ class nsImportGenericAddressBooks : publ
   static void SetLogs(nsString &success, nsString &error,
                       nsISupportsString *pSuccess, nsISupportsString *pError);
   static void ReportError(const char16_t *pName, nsString *pStream,
                           nsIStringBundle *aBundle);
 
  private:
   nsCOMPtr<nsIImportAddressBooks> m_pInterface;
   nsCOMPtr<nsIArray> m_Books;
-  nsCOMArray<nsIAddrDatabase> m_DBs;
+  nsCOMArray<nsIAbDirectory> m_DBs;
   nsCOMPtr<nsIFile> m_pLocation;
   nsCOMPtr<nsIImportFieldMap> m_pFieldMap;
   bool m_autoFind;
   char16_t *m_description;
   bool m_gotLocation;
   bool m_found;
   bool m_userVerify;
   nsCOMPtr<nsISupportsString> m_pSuccessLog;
@@ -62,17 +62,17 @@ class AddressThreadData {
  public:
   bool driverAlive;
   bool threadAlive;
   bool abort;
   bool fatalError;
   uint32_t currentTotal;
   uint32_t currentSize;
   nsCOMPtr<nsIArray> books;
-  nsCOMArray<nsIAddrDatabase> *dBs;
+  nsCOMArray<nsIAbDirectory> *dBs;
   nsCOMPtr<nsIAbLDIFService> ldifService;
   nsCOMPtr<nsIImportAddressBooks> addressImport;
   nsCOMPtr<nsIImportFieldMap> fieldMap;
   nsCOMPtr<nsISupportsString> successLog;
   nsCOMPtr<nsISupportsString> errorLog;
   nsCString pDestinationUri;
   nsCOMPtr<nsIStringBundle> stringBundle;
 
--- a/mailnews/import/src/nsImportFieldMap.cpp
+++ b/mailnews/import/src/nsImportFieldMap.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nscore.h"
+#include "nsIAbCard.h"
 #include "nsIStringBundle.h"
 #include "nsImportFieldMap.h"
 #include "nsImportStringBundle.h"
 #include "nsCRTGlue.h"
 #include "ImportDebug.h"
 #include "nsCOMPtr.h"
 
 ////////////////////////////////////////////////////////////////////////
@@ -155,155 +156,145 @@ NS_IMETHODIMP nsImportFieldMap::GetField
 
 NS_IMETHODIMP nsImportFieldMap::SetFieldActive(int32_t index, bool active) {
   if ((index < 0) || (index >= m_numFields)) return NS_ERROR_FAILURE;
 
   m_pActive[index] = active;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsImportFieldMap::SetFieldValue(nsIAddrDatabase *database,
-                                              nsIMdbRow *row, int32_t fieldNum,
-                                              const char16_t *value) {
-  NS_ASSERTION(database != nullptr, "null ptr");
-  NS_ASSERTION(row != nullptr, "null ptr");
-  NS_ASSERTION(value != nullptr, "null ptr");
-  if (!database || !row || !value) return NS_ERROR_NULL_POINTER;
-
+NS_IMETHODIMP nsImportFieldMap::SetFieldValue(nsIAbDirectory *database,
+                                              nsIAbCard *row, int32_t fieldNum,
+                                              const nsAString &value) {
   // Allow the special value for a null field
   if (fieldNum == -1) return NS_OK;
 
   if ((fieldNum < 0) || (fieldNum >= m_mozFieldCount)) return NS_ERROR_FAILURE;
 
   // UGGG!!!!! lot's of typing here!
   nsresult rv;
 
-  nsString str(value);
-  char *pVal = ToNewUTF8String(str);
-
   switch (fieldNum) {
     case 0:
-      rv = database->AddFirstName(row, pVal);
+      rv = row->SetFirstName(value);
       break;
     case 1:
-      rv = database->AddLastName(row, pVal);
+      rv = row->SetLastName(value);
       break;
     case 2:
-      rv = database->AddDisplayName(row, pVal);
+      rv = row->SetDisplayName(value);
       break;
     case 3:
-      rv = database->AddNickName(row, pVal);
+      rv = row->SetPropertyAsAString(kNicknameProperty, value);
       break;
     case 4:
-      rv = database->AddPrimaryEmail(row, pVal);
+      rv = row->SetPrimaryEmail(value);
       break;
     case 5:
-      rv = database->Add2ndEmail(row, pVal);
+      rv = row->SetPropertyAsAString(k2ndEmailProperty, value);
       break;
     case 6:
-      rv = database->AddWorkPhone(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkPhoneProperty, value);
       break;
     case 7:
-      rv = database->AddHomePhone(row, pVal);
+      rv = row->SetPropertyAsAString(kHomePhoneProperty, value);
       break;
     case 8:
-      rv = database->AddFaxNumber(row, pVal);
+      rv = row->SetPropertyAsAString(kFaxProperty, value);
       break;
     case 9:
-      rv = database->AddPagerNumber(row, pVal);
+      rv = row->SetPropertyAsAString(kPagerProperty, value);
       break;
     case 10:
-      rv = database->AddCellularNumber(row, pVal);
+      rv = row->SetPropertyAsAString(kCellularProperty, value);
       break;
     case 11:
-      rv = database->AddHomeAddress(row, pVal);
+      rv = row->SetPropertyAsAString(kHomeAddressProperty, value);
       break;
     case 12:
-      rv = database->AddHomeAddress2(row, pVal);
+      rv = row->SetPropertyAsAString(kHomeAddress2Property, value);
       break;
     case 13:
-      rv = database->AddHomeCity(row, pVal);
+      rv = row->SetPropertyAsAString(kHomeCityProperty, value);
       break;
     case 14:
-      rv = database->AddHomeState(row, pVal);
+      rv = row->SetPropertyAsAString(kHomeStateProperty, value);
       break;
     case 15:
-      rv = database->AddHomeZipCode(row, pVal);
+      rv = row->SetPropertyAsAString(kHomeZipCodeProperty, value);
       break;
     case 16:
-      rv = database->AddHomeCountry(row, pVal);
+      rv = row->SetPropertyAsAString(kHomeCountryProperty, value);
       break;
     case 17:
-      rv = database->AddWorkAddress(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkAddressProperty, value);
       break;
     case 18:
-      rv = database->AddWorkAddress2(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkAddress2Property, value);
       break;
     case 19:
-      rv = database->AddWorkCity(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkCityProperty, value);
       break;
     case 20:
-      rv = database->AddWorkState(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkStateProperty, value);
       break;
     case 21:
-      rv = database->AddWorkZipCode(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkZipCodeProperty, value);
       break;
     case 22:
-      rv = database->AddWorkCountry(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkCountryProperty, value);
       break;
     case 23:
-      rv = database->AddJobTitle(row, pVal);
+      rv = row->SetPropertyAsAString(kJobTitleProperty, value);
       break;
     case 24:
-      rv = database->AddDepartment(row, pVal);
+      rv = row->SetPropertyAsAString(kDepartmentProperty, value);
       break;
     case 25:
-      rv = database->AddCompany(row, pVal);
+      rv = row->SetPropertyAsAString(kCompanyProperty, value);
       break;
     case 26:
-      rv = database->AddWebPage1(row, pVal);
+      rv = row->SetPropertyAsAString(kWorkWebPageProperty, value);
       break;
     case 27:
-      rv = database->AddWebPage2(row, pVal);
+      rv = row->SetPropertyAsAString(kHomeWebPageProperty, value);
       break;
     case 28:
-      rv = database->AddBirthYear(row, pVal);
+      rv = row->SetPropertyAsAString(kBirthYearProperty, value);
       break;
     case 29:
-      rv = database->AddBirthMonth(row, pVal);
+      rv = row->SetPropertyAsAString(kBirthMonthProperty, value);
       break;
     case 30:
-      rv = database->AddBirthDay(row, pVal);
+      rv = row->SetPropertyAsAString(kBirthDayProperty, value);
       break;
     case 31:
-      rv = database->AddCustom1(row, pVal);
+      rv = row->SetPropertyAsAString(kCustom1Property, value);
       break;
     case 32:
-      rv = database->AddCustom2(row, pVal);
+      rv = row->SetPropertyAsAString(kCustom2Property, value);
       break;
     case 33:
-      rv = database->AddCustom3(row, pVal);
+      rv = row->SetPropertyAsAString(kCustom3Property, value);
       break;
     case 34:
-      rv = database->AddCustom4(row, pVal);
+      rv = row->SetPropertyAsAString(kCustom4Property, value);
       break;
     case 35:
-      rv = database->AddNotes(row, pVal);
+      rv = row->SetPropertyAsAString(kNotesProperty, value);
       break;
     case 36:
-      rv = database->AddAimScreenName(row, pVal);
+      rv = row->SetPropertyAsAString(kAIMProperty, value);
       break;
     default:
       /* Get the field description, and add it as an anonymous attr? */
       /* OR WHAT???? */
       { rv = NS_ERROR_FAILURE; }
   }
 
-  free(pVal);
-
   return rv;
 }
 
 nsresult nsImportFieldMap::Allocate(int32_t newSize) {
   if (newSize <= m_allocated) return NS_OK;
 
   int32_t sz = m_allocated;
   while (sz < newSize) sz += 30;
--- a/mailnews/import/src/nsImportFieldMap.h
+++ b/mailnews/import/src/nsImportFieldMap.h
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsImportFieldMap_h___
 #define nsImportFieldMap_h___
 
 #include "nscore.h"
 #include "nsIImportFieldMap.h"
-#include "nsIAddrDatabase.h"  // For SetFieldValue() arguments
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsIStringBundle.h"
 
 ////////////////////////////////////////////////////////////////////////
 
 class nsIStringBundle;
 
--- a/mailnews/import/test/unit/xpcshell.ini
+++ b/mailnews/import/test/unit/xpcshell.ini
@@ -8,16 +8,15 @@ support-files = resources/*
 [test_csv_GetSample.js]
 [test_becky_addressbook.js]
 run-if = os == 'win'
 [test_becky_filters.js]
 run-if = os == 'win'
 [test_csv_import.js]
 [test_csv_import_quote.js]
 [test_ldif_import.js]
-run-if = os == 'win'
 [test_outlook_settings.js]
 run-if = os == 'win'
 [test_shiftjis_csv.js]
 [test_utf16_csv.js]
 [test_vcard_import.js]
 [test_winmail.js]
 run-if = os == 'win'
--- a/mailnews/import/text/src/nsTextAddress.cpp
+++ b/mailnews/import/text/src/nsTextAddress.cpp
@@ -1,23 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "nsAbBaseCID.h"
 #include "nsTextAddress.h"
-#include "nsIAddrDatabase.h"
+#include "nsIAbDirectory.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsNetUtil.h"
 #include "nsMsgI18N.h"
 #include "nsMsgUtils.h"
-#include "mdb.h"
 #include "nsIConverterInputStream.h"
 #include "nsIUnicharLineInputStream.h"
 #include "nsMsgUtils.h"
 
 #include "ImportDebug.h"
 #include "plstr.h"
 #include "msgCore.h"
 
@@ -46,21 +46,22 @@ nsresult nsTextAddress::GetUnicharLineSt
         aInputStream, charset.get(), 8192,
         nsIConverterInputStream::DEFAULT_REPLACEMENT_CHARACTER);
   }
 
   return CallQueryInterface(converterStream, aStream);
 }
 
 nsresult nsTextAddress::ImportAddresses(bool *pAbort, const char16_t *pName,
-                                        nsIFile *pSrc, nsIAddrDatabase *pDb,
+                                        nsIFile *pSrc,
+                                        nsIAbDirectory *pDirectory,
                                         nsIImportFieldMap *fieldMap,
                                         nsString &errors, uint32_t *pProgress) {
   // Open the source file for reading, read each line and process it!
-  m_database = pDb;
+  m_directory = pDirectory;
   m_fieldMap = fieldMap;
 
   nsCOMPtr<nsIInputStream> inputStream;
   nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), pSrc);
   if (NS_FAILED(rv)) {
     IMPORT_LOG0("*** Error opening address file for reading\n");
     return rv;
   }
@@ -123,17 +124,17 @@ nsresult nsTextAddress::ImportAddresses(
   inputStream->Close();
 
   if (NS_FAILED(rv)) {
     IMPORT_LOG0(
         "*** Error reading the address book - probably incorrect ending\n");
     return NS_ERROR_FAILURE;
   }
 
-  return pDb->Commit(nsAddrDBCommitType::kLargeCommit);
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult nsTextAddress::ReadRecord(nsIUnicharLineInputStream *aLineStream,
                                    nsAString &aLine, bool *aMore) {
   bool more = true;
   uint32_t numQuotes = 0;
   nsresult rv;
   nsAutoString line;
@@ -385,43 +386,42 @@ nsresult nsTextAddress::ProcessLine(cons
     IMPORT_LOG0("*** Error, text import needs a field map\n");
     return NS_ERROR_FAILURE;
   }
 
   nsresult rv;
 
   // Wait until we get our first non-empty field, then create a new row,
   // fill in the data, then add the row to the database.
-  nsCOMPtr<nsIMdbRow> newRow;
+  nsCOMPtr<nsIAbCard> newCard;
   nsAutoString fieldVal;
   int32_t fieldNum;
   int32_t numFields = 0;
   bool active;
   rv = m_fieldMap->GetMapSize(&numFields);
   for (int32_t i = 0; (i < numFields) && NS_SUCCEEDED(rv); i++) {
     active = false;
     rv = m_fieldMap->GetFieldMap(i, &fieldNum);
     if (NS_SUCCEEDED(rv)) rv = m_fieldMap->GetFieldActive(i, &active);
     if (NS_SUCCEEDED(rv) && active) {
       if (GetField(aLine, i, fieldVal, m_delim)) {
         if (!fieldVal.IsEmpty()) {
-          if (!newRow) {
-            rv = m_database->GetNewRow(getter_AddRefs(newRow));
-            if (NS_FAILED(rv)) {
-              IMPORT_LOG0("*** Error getting new address database row\n");
-            }
+          if (!newCard) {
+            newCard = do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID, &rv);
           }
-          if (newRow) {
-            rv = m_fieldMap->SetFieldValue(m_database, newRow, fieldNum,
-                                           fieldVal.get());
+          if (newCard) {
+            rv = m_fieldMap->SetFieldValue(m_directory, newCard, fieldNum,
+                                           fieldVal);
           }
         }
-      } else
+      } else {
         break;
+      }
     } else if (active) {
       IMPORT_LOG1("*** Error getting field map for index %ld\n", (long)i);
     }
   }
 
-  if (NS_SUCCEEDED(rv) && newRow) rv = m_database->AddCardRowToDB(newRow);
+  nsIAbCard *outCard;
+  rv = m_directory->AddCard(newCard, &outCard);
 
   return rv;
 }
--- a/mailnews/import/text/src/nsTextAddress.h
+++ b/mailnews/import/text/src/nsTextAddress.h
@@ -7,33 +7,34 @@
 #ifndef nsTextAddress_h__
 #define nsTextAddress_h__
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIImportFieldMap.h"
 #include "nsIImportService.h"
 
-class nsIAddrDatabase;
+class nsIAbDirectory;
 class nsIFile;
 class nsIInputStream;
 class nsIUnicharLineInputStream;
 
 /////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////
 
 class nsTextAddress {
  public:
   nsTextAddress();
   virtual ~nsTextAddress();
 
   nsresult ImportAddresses(bool *pAbort, const char16_t *pName, nsIFile *pSrc,
-                           nsIAddrDatabase *pDb, nsIImportFieldMap *fieldMap,
-                           nsString &errors, uint32_t *pProgress);
+                           nsIAbDirectory *pDirectory,
+                           nsIImportFieldMap *fieldMap, nsString &errors,
+                           uint32_t *pProgress);
 
   nsresult DetermineDelim(nsIFile *pSrc);
   char16_t GetDelim(void) { return m_delim; }
 
   static nsresult ReadRecordNumber(nsIFile *pSrc, nsAString &aLine,
                                    int32_t rNum);
   static bool GetField(const nsAString &aLine, int32_t index, nsString &field,
                        char16_t delim);
@@ -46,14 +47,14 @@ class nsTextAddress {
                              bool *aMore);
   static nsresult GetUnicharLineStreamForFile(
       nsIFile *aFile, nsIInputStream *aInputStream,
       nsIUnicharLineInputStream **aStream);
 
   char16_t m_delim;
   int32_t m_LFCount;
   int32_t m_CRCount;
-  nsCOMPtr<nsIAddrDatabase> m_database;
+  nsCOMPtr<nsIAbDirectory> m_directory;
   nsCOMPtr<nsIImportFieldMap> m_fieldMap;
   nsCOMPtr<nsIImportService> m_pService;
 };
 
 #endif /* nsTextAddress_h__ */
--- a/mailnews/import/text/src/nsTextImport.cpp
+++ b/mailnews/import/text/src/nsTextImport.cpp
@@ -13,17 +13,16 @@
 #include "nsIImportService.h"
 #include "nsMsgI18N.h"
 #include "nsTextImport.h"
 #include "nsIMutableArray.h"
 #include "nsIImportGeneric.h"
 #include "nsIImportAddressBooks.h"
 #include "nsIImportABDescriptor.h"
 #include "nsIImportFieldMap.h"
-#include "nsIAddrDatabase.h"
 #include "nsIAbLDIFService.h"
 #include "nsAbBaseCID.h"
 #include "nsTextFormatter.h"
 #include "nsImportStringBundle.h"
 #include "nsTextAddress.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "ImportDebug.h"
@@ -63,17 +62,17 @@ class ImportAddressImpl final : public n
   NS_IMETHOD GetDefaultLocation(nsIFile **location, bool *found,
                                 bool *userVerify) override;
 
   NS_IMETHOD FindAddressBooks(nsIFile *location, nsIArray **_retval) override;
 
   NS_IMETHOD InitFieldMap(nsIImportFieldMap *fieldMap) override;
 
   NS_IMETHOD ImportAddressBook(nsIImportABDescriptor *source,
-                               nsIAddrDatabase *destination,
+                               nsIAbDirectory *destination,
                                nsIImportFieldMap *fieldMap,
                                nsISupports *aSupportService,
                                char16_t **errorLog, char16_t **successLog,
                                bool *fatalError) override;
 
   NS_IMETHOD GetImportProgress(uint32_t *_retval) override;
 
   NS_IMETHOD GetSampleData(int32_t index, bool *pFound,
@@ -328,17 +327,17 @@ void ImportAddressImpl::ReportError(int3
 void ImportAddressImpl::SetLogs(nsString &success, nsString &error,
                                 char16_t **pError, char16_t **pSuccess) {
   if (pError) *pError = ToNewUnicode(error);
   if (pSuccess) *pSuccess = ToNewUnicode(success);
 }
 
 NS_IMETHODIMP
 ImportAddressImpl::ImportAddressBook(nsIImportABDescriptor *pSource,
-                                     nsIAddrDatabase *pDestination,
+                                     nsIAbDirectory *pDestination,
                                      nsIImportFieldMap *fieldMap,
                                      nsISupports *aSupportService,
                                      char16_t **pErrorLog,
                                      char16_t **pSuccessLog, bool *fatalError) {
   NS_ASSERTION(pSource != nullptr, "null ptr");
   NS_ASSERTION(pDestination != nullptr, "null ptr");
   NS_ASSERTION(fatalError != nullptr, "null ptr");
 
--- a/mailnews/import/vcard/src/nsVCardAddress.cpp
+++ b/mailnews/import/vcard/src/nsVCardAddress.cpp
@@ -4,31 +4,32 @@
 
 #include "nsAbBaseCID.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsNetUtil.h"
 #include "nsVCardAddress.h"
 
 #include "nsIAbCard.h"
 #include "nsIAbManager.h"
-#include "nsIAddrDatabase.h"
+#include "nsIAbDirectory.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsILineInputStream.h"
 
 #include "plstr.h"
 #include "msgCore.h"
 #include "nsMsgUtils.h"
 
 nsVCardAddress::nsVCardAddress() {}
 
 nsVCardAddress::~nsVCardAddress() {}
 
 nsresult nsVCardAddress::ImportAddresses(bool *pAbort, const char16_t *pName,
-                                         nsIFile *pSrc, nsIAddrDatabase *pDb,
+                                         nsIFile *pSrc,
+                                         nsIAbDirectory *pDirectory,
                                          nsString &errors,
                                          uint32_t *pProgress) {
   // Open the source file for reading, read each line and process it!
   nsCOMPtr<nsIInputStream> inputStream;
   nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), pSrc);
   if (NS_FAILED(rv)) {
     IMPORT_LOG0("*** Error opening address file for reading\n");
     return rv;
@@ -59,17 +60,18 @@ nsresult nsVCardAddress::ImportAddresses
     rv = ReadRecord(lineStream, record, &more);
     if (NS_SUCCEEDED(rv) && !record.IsEmpty()) {
       // Parse the vCard and build an nsIAbCard from it
       nsCOMPtr<nsIAbCard> cardFromVCard;
       rv =
           ab->EscapedVCardToAbCard(record.get(), getter_AddRefs(cardFromVCard));
       NS_ENSURE_SUCCESS(rv, rv);
 
-      rv = pDb->CreateNewCardAndAddToDB(cardFromVCard, false, nullptr);
+      nsIAbCard *outCard;
+      rv = pDirectory->AddCard(cardFromVCard, &outCard);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (NS_FAILED(rv)) {
         IMPORT_LOG0("*** Error processing vCard record.\n");
       }
     }
     if (NS_SUCCEEDED(rv) && pProgress) {
       // This won't be totally accurate, but its the best we can do
@@ -82,17 +84,17 @@ nsresult nsVCardAddress::ImportAddresses
   inputStream->Close();
 
   if (NS_FAILED(rv)) {
     IMPORT_LOG0(
         "*** Error reading the address book - probably incorrect ending\n");
     return NS_ERROR_FAILURE;
   }
 
-  return pDb->Commit(nsAddrDBCommitType::kLargeCommit);
+  return NS_OK;
 }
 
 nsresult nsVCardAddress::ReadRecord(nsILineInputStream *aLineStream,
                                     nsCString &aRecord, bool *aMore) {
   bool more = true;
   nsresult rv;
   nsCString line;
 
--- a/mailnews/import/vcard/src/nsVCardAddress.h
+++ b/mailnews/import/vcard/src/nsVCardAddress.h
@@ -2,27 +2,27 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsVCardAddress_h__
 #define nsVCardAddress_h__
 
 #include "ImportDebug.h"
 
-class nsIAddrDatabase;
+class nsIAbDirectory;
 class nsIFile;
 class nsILineInputStream;
 
 class nsVCardAddress {
  public:
   nsVCardAddress();
   virtual ~nsVCardAddress();
 
   nsresult ImportAddresses(bool *pAbort, const char16_t *pName, nsIFile *pSrc,
-                           nsIAddrDatabase *pDb, nsString &errors,
+                           nsIAbDirectory *pDirectory, nsString &errors,
                            uint32_t *pProgress);
 
  private:
   static nsresult ReadRecord(nsILineInputStream *aLineStream,
                              nsCString &aRecord, bool *aMore);
 };
 
 #endif /* nsVCardAddress_h__ */
--- a/mailnews/import/vcard/src/nsVCardImport.cpp
+++ b/mailnews/import/vcard/src/nsVCardImport.cpp
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
   VCard import addressbook interfaces
 */
 #include "nscore.h"
-#include "nsIAddrDatabase.h"
 #include "nsIFile.h"
 #include "nsIImportABDescriptor.h"
 #include "nsIImportAddressBooks.h"
 #include "nsIImportFieldMap.h"
 #include "nsIImportGeneric.h"
 #include "nsIMutableArray.h"
 #include "nsCOMPtr.h"
 #include "nsIImportService.h"
@@ -55,17 +54,17 @@ class ImportVCardAddressImpl : public ns
 
   NS_IMETHOD FindAddressBooks(nsIFile *location, nsIArray **_retval) override;
 
   NS_IMETHOD InitFieldMap(nsIImportFieldMap *fieldMap) override {
     return NS_ERROR_FAILURE;
   }
 
   NS_IMETHOD ImportAddressBook(nsIImportABDescriptor *source,
-                               nsIAddrDatabase *destination,
+                               nsIAbDirectory *destination,
                                nsIImportFieldMap *fieldMap,
                                nsISupports *aSupportService,
                                char16_t **errorLog, char16_t **successLog,
                                bool *fatalError) override;
 
   NS_IMETHOD GetImportProgress(uint32_t *_retval) override;
 
   NS_IMETHOD GetSampleData(int32_t index, bool *pFound,
@@ -296,17 +295,17 @@ void ImportVCardAddressImpl::ReportError
 
 void ImportVCardAddressImpl::SetLogs(nsString &success, nsString &error,
                                      char16_t **pError, char16_t **pSuccess) {
   if (pError) *pError = ToNewUnicode(error);
   if (pSuccess) *pSuccess = ToNewUnicode(success);
 }
 
 NS_IMETHODIMP ImportVCardAddressImpl::ImportAddressBook(
-    nsIImportABDescriptor *pSource, nsIAddrDatabase *pDestination,
+    nsIImportABDescriptor *pSource, nsIAbDirectory *pDestination,
     nsIImportFieldMap *fieldMap, nsISupports *aSupportService,
     char16_t **pErrorLog, char16_t **pSuccessLog, bool *fatalError) {
   NS_ENSURE_ARG_POINTER(pSource);
   NS_ENSURE_ARG_POINTER(pDestination);
   NS_ENSURE_ARG_POINTER(fatalError);
 
   if (!m_notProxyBundle) return NS_ERROR_FAILURE;