Bug 684455 - Import from Becky! Internet Mail. r?mkato, rs=rkent
☠☠ backed out by 1a8b3bd56c13 ☠ ☠
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Fri, 13 May 2016 07:24:19 +0200
changeset 19311 53135577a75a21f8a97290a6d4669075a3037879
parent 19310 6f156e84d899ff6057c883fae21b3b71970cd0c7
child 19312 beac1b52a9251c346820d41d80a83b6037dbd1fd
push id11874
push useracelists@atlas.sk
push dateFri, 13 May 2016 05:25:10 +0000
treeherdercomm-central@beac1b52a925 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmkato, rkent
bugs684455
Bug 684455 - Import from Becky! Internet Mail. r?mkato, rs=rkent
mail/locales/en-US/chrome/messenger/beckyImportMsgs.properties
mail/locales/jar.mn
mailnews/import/becky/src/moz.build
mailnews/import/becky/src/nsBeckyAddressBooks.cpp
mailnews/import/becky/src/nsBeckyAddressBooks.h
mailnews/import/becky/src/nsBeckyFilters.cpp
mailnews/import/becky/src/nsBeckyFilters.h
mailnews/import/becky/src/nsBeckyImport.cpp
mailnews/import/becky/src/nsBeckyImport.h
mailnews/import/becky/src/nsBeckyMail.cpp
mailnews/import/becky/src/nsBeckyMail.h
mailnews/import/becky/src/nsBeckySettings.cpp
mailnews/import/becky/src/nsBeckySettings.h
mailnews/import/becky/src/nsBeckyStringBundle.cpp
mailnews/import/becky/src/nsBeckyStringBundle.h
mailnews/import/becky/src/nsBeckyUtils.cpp
mailnews/import/becky/src/nsBeckyUtils.h
mailnews/import/build/moz.build
mailnews/import/build/nsImportModule.cpp
mailnews/import/vcard/src/moz.build
mailnews/moz.build
new file mode 100644
--- /dev/null
+++ b/mail/locales/en-US/chrome/messenger/beckyImportMsgs.properties
@@ -0,0 +1,19 @@
+# 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/.
+#
+# The following are used by the becky import code to display status/error
+# and informational messages
+
+# Short name of import module
+BeckyImportName=Becky! Internet Mail
+
+# Description of import module
+BeckyImportDescription=Import Local Mail from Becky! Internet Mail
+
+# Success Message
+# LOCALIZATION NOTE : Do not translate the word "%S" below.
+# The variable %S will contain the name of the Mailbox
+BeckyImportMailboxSuccess=Local messages were successfully imported from %S.
+
+BeckyImportAddressSuccess=Address book imported
--- a/mail/locales/jar.mn
+++ b/mail/locales/jar.mn
@@ -100,16 +100,17 @@
   locale/@AB_CD@/messenger/importDialog.dtd                             (%chrome/messenger/importDialog.dtd)
   locale/@AB_CD@/messenger/fieldMapImport.dtd                           (%chrome/messenger/fieldMapImport.dtd)
   locale/@AB_CD@/messenger/textImportMsgs.properties                    (%chrome/messenger/textImportMsgs.properties)
   locale/@AB_CD@/messenger/vCardImportMsgs.properties                   (%chrome/messenger/vCardImportMsgs.properties)
   locale/@AB_CD@/messenger/appleMailImportMsgs.properties               (%chrome/messenger/appleMailImportMsgs.properties)
   locale/@AB_CD@/messenger/oeImportMsgs.properties                      (%chrome/messenger/oeImportMsgs.properties)
   locale/@AB_CD@/messenger/wmImportMsgs.properties                      (%chrome/messenger/wmImportMsgs.properties)
   locale/@AB_CD@/messenger/outlookImportMsgs.properties                 (%chrome/messenger/outlookImportMsgs.properties)
+  locale/@AB_CD@/messenger/beckyImportMsgs.properties                   (%chrome/messenger/beckyImportMsgs.properties)
   locale/@AB_CD@/messenger/shutdownWindow.properties                    (%chrome/messenger/shutdownWindow.properties)
   locale/@AB_CD@/messenger/configEditorOverlay.dtd                      (%chrome/messenger/configEditorOverlay.dtd)
   locale/@AB_CD@/messenger/gloda.properties                             (%chrome/messenger/gloda.properties)
   locale/@AB_CD@/messenger/glodaComplete.properties                     (%chrome/messenger/glodaComplete.properties)
   locale/@AB_CD@/messenger/templateUtils.properties                     (%chrome/messenger/templateUtils.properties)
   locale/@AB_CD@/messenger/glodaFacetView.properties                    (%chrome/messenger/glodaFacetView.properties)
   locale/@AB_CD@/messenger/glodaFacetView.dtd                           (%chrome/messenger/glodaFacetView.dtd)
   locale/@AB_CD@/messenger/quickFilterBar.dtd                           (%chrome/messenger/quickFilterBar.dtd)
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/moz.build
@@ -0,0 +1,16 @@
+# vim: set filetype=python:
+# 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/.
+
+UNIFIED_SOURCES += [
+    'nsBeckyAddressBooks.cpp',
+    'nsBeckyFilters.cpp',
+    'nsBeckyImport.cpp',
+    'nsBeckyMail.cpp',
+    'nsBeckySettings.cpp',
+    'nsBeckyStringBundle.cpp',
+    'nsBeckyUtils.cpp',
+]
+
+FINAL_LIBRARY = 'import'
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyAddressBooks.cpp
@@ -0,0 +1,364 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsCOMPtr.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIFile.h"
+#include "nsISimpleEnumerator.h"
+#include "nsIDirectoryEnumerator.h"
+#include "nsIMutableArray.h"
+#include "nsStringGlue.h"
+#include "nsAbBaseCID.h"
+#include "nsIAbManager.h"
+#include "nsIImportService.h"
+#include "nsIImportABDescriptor.h"
+#include "nsMsgUtils.h"
+#include "nsIStringBundle.h"
+#include "nsVCardAddress.h"
+
+#include "nsBeckyAddressBooks.h"
+#include "nsBeckyStringBundle.h"
+#include "nsBeckyUtils.h"
+
+NS_IMPL_ISUPPORTS(nsBeckyAddressBooks, nsIImportAddressBooks)
+
+nsresult
+nsBeckyAddressBooks::Create(nsIImportAddressBooks **aImport)
+{
+  NS_ENSURE_ARG_POINTER(aImport);
+
+  *aImport = new nsBeckyAddressBooks();
+
+  NS_ADDREF(*aImport);
+  return NS_OK;
+}
+
+nsBeckyAddressBooks::nsBeckyAddressBooks()
+: mReadBytes(0)
+{
+}
+
+nsBeckyAddressBooks::~nsBeckyAddressBooks()
+{
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::GetSupportsMultiple(bool *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+  *_retval = false;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::GetAutoFind(char16_t **aDescription,
+                                 bool *_retval)
+{
+  NS_ENSURE_ARG_POINTER(aDescription);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  *aDescription =
+    nsBeckyStringBundle::GetStringByName(MOZ_UTF16("BeckyImportDescription"));
+  *_retval = false;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::GetNeedsFieldMap(nsIFile *aLocation, bool *_retval)
+{
+  *_retval = false;
+  return NS_OK;
+}
+
+nsresult
+nsBeckyAddressBooks::FindAddressBookDirectory(nsIFile **aAddressBookDirectory)
+{
+  nsCOMPtr<nsIFile> userDirectory;
+  nsresult rv = nsBeckyUtils::FindUserDirectory(getter_AddRefs(userDirectory));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = userDirectory->Append(NS_LITERAL_STRING("AddrBook"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists;
+  rv = userDirectory->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  userDirectory.forget(aAddressBookDirectory);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::GetDefaultLocation(nsIFile **aLocation,
+                                        bool *aFound,
+                                        bool *aUserVerify)
+{
+  NS_ENSURE_ARG_POINTER(aFound);
+  NS_ENSURE_ARG_POINTER(aLocation);
+  NS_ENSURE_ARG_POINTER(aUserVerify);
+
+  *aLocation = nullptr;
+  *aFound = false;
+  *aUserVerify = true;
+
+  if (NS_SUCCEEDED(nsBeckyAddressBooks::FindAddressBookDirectory(aLocation))) {
+    *aFound = true;
+    *aUserVerify = false;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyAddressBooks::CreateAddressBookDescriptor(nsIImportABDescriptor **aDescriptor)
+{
+  nsresult rv;
+  nsCOMPtr<nsIImportService> importService = do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return importService->CreateNewABDescriptor(aDescriptor);
+}
+
+bool
+nsBeckyAddressBooks::IsAddressBookFile(nsIFile *aFile)
+{
+  nsresult rv;
+  bool isDirectory = false;
+  rv = aFile->IsDirectory(&isDirectory);
+  if (NS_SUCCEEDED(rv) && isDirectory)
+    return false;
+
+  nsAutoString name;
+  rv = aFile->GetLeafName(name);
+  return StringEndsWith(name, NS_LITERAL_STRING(".bab"));
+}
+
+bool
+nsBeckyAddressBooks::HasAddressBookFile(nsIFile *aDirectory)
+{
+  nsresult rv;
+  bool isDirectory = false;
+  rv = aDirectory->IsDirectory(&isDirectory);
+  if (NS_FAILED(rv) || !isDirectory)
+    return false;
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  bool more;
+  nsCOMPtr<nsISupports> entry;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
+    rv = entries->GetNext(getter_AddRefs(entry));
+    NS_ENSURE_SUCCESS(rv, false);
+
+    nsCOMPtr<nsIFile> file = do_QueryInterface(entry, &rv);
+    NS_ENSURE_SUCCESS(rv, false);
+    if (IsAddressBookFile(file))
+      return true;
+  }
+
+  return false;
+}
+
+uint32_t
+nsBeckyAddressBooks::CountAddressBookSize(nsIFile *aDirectory)
+{
+  nsresult rv;
+  bool isDirectory = false;
+  rv = aDirectory->IsDirectory(&isDirectory);
+  if (NS_FAILED(rv) || !isDirectory)
+    return 0;
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS(rv, 0);
+
+  uint32_t total = 0;
+  bool more;
+  nsCOMPtr<nsISupports> entry;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
+    rv = entries->GetNext(getter_AddRefs(entry));
+    NS_ENSURE_SUCCESS(rv, 0);
+
+    nsCOMPtr<nsIFile> file = do_QueryInterface(entry, &rv);
+    NS_ENSURE_SUCCESS(rv, 0);
+
+    int64_t size;
+    file->GetFileSize(&size);
+    if (total + size > std::numeric_limits<uint32_t>::max())
+      return std::numeric_limits<uint32_t>::max();
+
+    total += static_cast<uint32_t>(size);
+  }
+
+  return total;
+}
+
+nsresult
+nsBeckyAddressBooks::AppendAddressBookDescriptor(nsIFile *aEntry,
+                                                 nsIMutableArray *aCollected)
+{
+  if (!HasAddressBookFile(aEntry))
+    return NS_OK;
+
+  nsresult rv;
+  nsCOMPtr<nsIImportABDescriptor> descriptor;
+  rv = CreateAddressBookDescriptor(getter_AddRefs(descriptor));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint32_t size = CountAddressBookSize(aEntry);
+  descriptor->SetSize(size);
+  descriptor->SetAbFile(aEntry);
+
+  nsAutoString name;
+  aEntry->GetLeafName(name);
+  descriptor->SetPreferredName(name);
+
+  return aCollected->AppendElement(descriptor, false);
+}
+
+nsresult
+nsBeckyAddressBooks::CollectAddressBooks(nsIFile *aTarget,
+                                         nsIMutableArray *aCollected)
+{
+  nsresult rv = AppendAddressBookDescriptor(aTarget, aCollected);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = aTarget->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more;
+  nsCOMPtr<nsISupports> entry;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
+    rv = entries->GetNext(getter_AddRefs(entry));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFile> file = do_QueryInterface(entry, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    bool isDirectory = false;
+    rv = file->IsDirectory(&isDirectory);
+    if (NS_SUCCEEDED(rv) && isDirectory)
+      rv = CollectAddressBooks(file, aCollected);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::FindAddressBooks(nsIFile *aLocation,
+                                      nsIArray **_retval)
+{
+  NS_ENSURE_ARG_POINTER(aLocation);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsresult rv;
+  nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool isDirectory = false;
+  rv = aLocation->IsDirectory(&isDirectory);
+  if (NS_FAILED(rv) || !isDirectory)
+    return NS_ERROR_FAILURE;
+
+  rv = CollectAddressBooks(aLocation, array);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  array.forget(_retval);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::InitFieldMap(nsIImportFieldMap *aFieldMap)
+{
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::ImportAddressBook(nsIImportABDescriptor *aSource,
+                                       nsIAddrDatabase *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);
+
+  mReadBytes = 0;
+
+  nsCOMPtr<nsIFile> file;
+  nsresult rv = aSource->GetAbFile(getter_AddRefs(file));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = file->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more;
+  nsCOMPtr<nsISupports> entry;
+  nsAutoString error;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
+    rv = entries->GetNext(getter_AddRefs(entry));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFile> file = do_QueryInterface(entry, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!IsAddressBookFile(file))
+      continue;
+
+    bool aborted = false;
+    nsAutoString name;
+    aSource->GetPreferredName(name);
+    nsVCardAddress vcard;
+    rv = vcard.ImportAddresses(&aborted, name.get(), file, aDestination, error, &mReadBytes);
+    if (NS_FAILED(rv)) {
+      break;
+    }
+  }
+
+  if (!error.IsEmpty())
+    *aErrorLog = ToNewUnicode(error);
+  else
+    *aSuccessLog = nsBeckyStringBundle::GetStringByName(MOZ_UTF16("BeckyImportAddressSuccess"));
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::GetImportProgress(uint32_t *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+  *_retval = mReadBytes;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::SetSampleLocation(nsIFile *aLocation)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyAddressBooks::GetSampleData(int32_t aRecordNumber,
+                                   bool *aRecordExists,
+                                   char16_t **_retval)
+{
+  return NS_ERROR_FAILURE;
+}
+
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyAddressBooks.h
@@ -0,0 +1,35 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsBeckyAddressBooks_h___
+#define nsBeckyAddressBooks_h___
+
+#include "nsIImportAddressBooks.h"
+
+class nsBeckyAddressBooks final : public nsIImportAddressBooks
+{
+public:
+  nsBeckyAddressBooks();
+  static nsresult Create(nsIImportAddressBooks **aImport);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIIMPORTADDRESSBOOKS
+
+private:
+  virtual ~nsBeckyAddressBooks();
+
+  uint32_t mReadBytes;
+
+  nsresult CollectAddressBooks(nsIFile *aTarget, nsIMutableArray *aCollected);
+  nsresult FindAddressBookDirectory(nsIFile **aAddressBookDirectory);
+  nsresult AppendAddressBookDescriptor(nsIFile *aEntry,
+                                       nsIMutableArray *aCollected);
+  uint32_t CountAddressBookSize(nsIFile *aDirectory);
+  bool HasAddressBookFile(nsIFile *aDirectory);
+  bool IsAddressBookFile(nsIFile *aFile);
+  nsresult CreateAddressBookDescriptor(nsIImportABDescriptor **aDescriptor);
+};
+
+#endif /* nsBeckyAddressBooks_h___ */
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyFilters.cpp
@@ -0,0 +1,691 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsArrayUtils.h"
+#include "nsILineInputStream.h"
+#include "nsIStringBundle.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIMsgFilter.h"
+#include "nsIMsgFilterList.h"
+#include "nsIMsgAccountManager.h"
+#include "nsIMsgAccount.h"
+#include "nsIMsgSearchTerm.h"
+#include "nsIMsgFolder.h"
+#include "nsCOMPtr.h"
+#include "nsMsgSearchCore.h"
+#include "nsMsgBaseCID.h"
+#include "nsMsgUtils.h"
+#include "msgCore.h"
+
+#include "nsBeckyFilters.h"
+#include "nsBeckyStringBundle.h"
+#include "nsBeckyUtils.h"
+
+NS_IMPL_ISUPPORTS(nsBeckyFilters, nsIImportFilters)
+
+nsresult
+nsBeckyFilters::Create(nsIImportFilters **aImport)
+{
+  NS_ENSURE_ARG_POINTER(aImport);
+
+  *aImport = new nsBeckyFilters();
+
+  NS_ADDREF(*aImport);
+  return NS_OK;
+}
+
+nsBeckyFilters::nsBeckyFilters()
+: mLocation(nullptr),
+  mServer(nullptr),
+  mConvertedFile(nullptr)
+{
+}
+
+nsBeckyFilters::~nsBeckyFilters()
+{
+}
+
+nsresult
+nsBeckyFilters::GetDefaultFilterFile(nsIFile **aFile)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> filter;
+  rv = nsBeckyUtils::GetDefaultMailboxDirectory(getter_AddRefs(filter));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = filter->Append(NS_LITERAL_STRING("IFilter.def"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists;
+  rv = filter->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  filter.forget(aFile);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyFilters::AutoLocate(char16_t **aDescription,
+                           nsIFile **aLocation,
+                           bool *_retval)
+{
+  NS_ENSURE_ARG_POINTER(aDescription);
+  NS_ENSURE_ARG_POINTER(aLocation);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  *aDescription =
+    nsBeckyStringBundle::GetStringByName(MOZ_UTF16("BeckyImportDescription"));
+  *aLocation = nullptr;
+  *_retval = false;
+
+  nsresult rv;
+  nsCOMPtr<nsIFile> location;
+  rv = GetDefaultFilterFile(getter_AddRefs(location));
+  if (NS_FAILED(rv))
+    location = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+  else
+    *_retval = true;
+
+  location.forget(aLocation);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyFilters::SetLocation(nsIFile *aLocation)
+{
+  mLocation = aLocation;
+  return NS_OK;
+}
+
+static nsMsgSearchAttribValue
+ConvertSearchKeyToAttrib(const nsACString &aKey)
+{
+  if (aKey.EqualsLiteral("From") ||
+      aKey.EqualsLiteral("Sender") ||
+      aKey.EqualsLiteral("From, Sender, X-Sender")) {
+    return nsMsgSearchAttrib::Sender;
+  } else if (aKey.EqualsLiteral("Subject")) {
+    return nsMsgSearchAttrib::Subject;
+  } else if (aKey.EqualsLiteral("[body]")) {
+    return nsMsgSearchAttrib::Body;
+  } else if (aKey.EqualsLiteral("Date")) {
+    return nsMsgSearchAttrib::Date;
+  } else if (aKey.EqualsLiteral("To")) {
+    return nsMsgSearchAttrib::To;
+  } else if (aKey.EqualsLiteral("Cc")) {
+    return nsMsgSearchAttrib::CC;
+  } else if (aKey.EqualsLiteral("To,  Cc,  Bcc:")) {
+    return nsMsgSearchAttrib::ToOrCC;
+  }
+  return -1;
+}
+
+static nsMsgSearchOpValue
+ConvertSearchFlagsToOperator(const nsACString &aFlags)
+{
+  nsCString flags(aFlags);
+  int32_t lastTabPosition = flags.RFindChar('\t');
+  if ((lastTabPosition == -1) ||
+      ((int32_t)aFlags.Length() == lastTabPosition - 1)) {
+    return -1;
+  }
+
+  switch (aFlags.CharAt(0)) {
+    case 'X':
+      return nsMsgSearchOp::DoesntContain;
+    case 'O':
+      if (aFlags.FindChar('T', lastTabPosition + 1) >= 0)
+        return nsMsgSearchOp::BeginsWith;
+      return nsMsgSearchOp::Contains;
+    default:
+      return -1;
+  }
+}
+
+nsresult
+nsBeckyFilters::ParseRuleLine(const nsCString &aLine,
+                              nsMsgSearchAttribValue *aSearchAttribute,
+                              nsMsgSearchOpValue *aSearchOperator,
+                              nsString &aSearchKeyword)
+{
+  int32_t firstColonPosition = aLine.FindChar(':');
+  if (firstColonPosition == -1 ||
+      (int32_t)aLine.Length() == firstColonPosition - 1) {
+    return NS_ERROR_FAILURE;
+  }
+
+  int32_t secondColonPosition = aLine.FindChar(':', firstColonPosition + 1);
+  if (secondColonPosition == -1 ||
+      (int32_t)aLine.Length() == secondColonPosition - 1) {
+    return NS_ERROR_FAILURE;
+  }
+
+  int32_t length = secondColonPosition - firstColonPosition - 1;
+  nsMsgSearchAttribValue searchAttribute;
+  searchAttribute = ConvertSearchKeyToAttrib(Substring(aLine, firstColonPosition + 1, length));
+  if (searchAttribute < 0)
+    return NS_ERROR_FAILURE;
+
+  int32_t tabPosition = aLine.FindChar('\t');
+  if (tabPosition == -1 ||
+      (int32_t)aLine.Length() == tabPosition - 1) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsMsgSearchOpValue searchOperator;
+  searchOperator = ConvertSearchFlagsToOperator(Substring(aLine, tabPosition + 1));
+  if (searchOperator < 0)
+    return NS_ERROR_FAILURE;
+
+  *aSearchOperator = searchOperator;
+  *aSearchAttribute = searchAttribute;
+  length = tabPosition - secondColonPosition - 1;
+  CopyUTF8toUTF16(Substring(aLine, secondColonPosition + 1, length), aSearchKeyword);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::SetSearchTerm(const nsCString &aLine, nsIMsgFilter *aFilter)
+{
+  NS_ENSURE_ARG_POINTER(aFilter);
+
+  nsresult rv;
+  nsMsgSearchAttribValue searchAttribute = -1;
+  nsMsgSearchOpValue searchOperator = -1;
+  nsAutoString searchKeyword;
+  rv = ParseRuleLine(aLine, &searchAttribute, &searchOperator, searchKeyword);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgSearchTerm> term;
+  rv = aFilter->CreateTerm(getter_AddRefs(term));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = term->SetAttrib(searchAttribute);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = term->SetOp(searchOperator);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgSearchValue> value;
+  rv = term->GetValue(getter_AddRefs(value));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = value->SetAttrib(searchAttribute);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = value->SetStr(searchKeyword);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = term->SetValue(value);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = term->SetBooleanAnd(false);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!searchKeyword.IsEmpty())
+    rv = aFilter->SetFilterName(searchKeyword);
+  else
+    rv = aFilter->SetFilterName(NS_LITERAL_STRING("No name"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return aFilter->AppendTerm(term);
+}
+
+nsresult
+nsBeckyFilters::CreateRuleAction(nsIMsgFilter *aFilter,
+                                 nsMsgRuleActionType actionType,
+                                 nsIMsgRuleAction **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIMsgRuleAction> action;
+  rv = aFilter->CreateAction(getter_AddRefs(action));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = action->SetType(actionType);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  action.forget(_retval);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::GetActionTarget(const nsCString &aLine,
+                                nsCString &aTarget)
+{
+  int32_t firstColonPosition = aLine.FindChar(':');
+  if (firstColonPosition < -1 ||
+      aLine.Length() == static_cast<uint32_t>(firstColonPosition)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  aTarget.Assign(Substring(aLine, firstColonPosition + 1));
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::GetResendTarget(const nsCString &aLine,
+                                nsCString &aTemplate,
+                                nsCString &aTargetAddress)
+{
+  nsresult rv;
+  nsAutoCString target;
+  rv = GetActionTarget(aLine, target);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  int32_t asteriskPosition = target.FindChar('*');
+  if (asteriskPosition < 0) {
+    aTemplate.Assign(target);
+    return NS_OK;
+  }
+
+  if (target.Length() == static_cast<uint32_t>(asteriskPosition))
+    return NS_ERROR_FAILURE;
+
+  aTemplate.Assign(StringHead(target, asteriskPosition - 1));
+  aTargetAddress.Assign(Substring(target, asteriskPosition + 1));
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::CreateResendAction(const nsCString &aLine,
+                                   nsIMsgFilter *aFilter,
+                                   const nsMsgRuleActionType &aActionType,
+                                   nsIMsgRuleAction **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIMsgRuleAction> action;
+  rv = CreateRuleAction(aFilter, aActionType, getter_AddRefs(action));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString templateString;
+  nsAutoCString targetAddress;
+  rv = GetResendTarget(aLine, templateString, targetAddress);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aActionType == nsMsgFilterAction::Forward)
+    rv = action->SetStrValue(targetAddress);
+  else
+    rv = action->SetStrValue(templateString);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  action.forget(_retval);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::GetFolderNameFromTarget(const nsCString &aTarget, nsAString &aName)
+{
+  int32_t backslashPosition = aTarget.RFindChar('\\');
+  if (backslashPosition > 0) {
+    NS_ConvertUTF8toUTF16 utf16String(Substring(aTarget, backslashPosition + 1));
+    nsBeckyUtils::TranslateFolderName(utf16String, aName);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::GetDistributeTarget(const nsCString &aLine,
+                                    nsCString &aTargetFolder)
+{
+  nsresult rv;
+  nsAutoCString target;
+  rv = GetActionTarget(aLine, target);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  target.Trim("\\", false, true);
+  nsAutoString folderName;
+  rv = GetFolderNameFromTarget(target, folderName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr <nsIMsgFolder> folder;
+  rv = GetMessageFolder(folderName, getter_AddRefs(folder));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!folder) {
+    rv = mServer->GetRootMsgFolder(getter_AddRefs(folder));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  return folder->GetURI(aTargetFolder);
+}
+
+nsresult
+nsBeckyFilters::CreateDistributeAction(const nsCString &aLine,
+                                       nsIMsgFilter *aFilter,
+                                       const nsMsgRuleActionType &aActionType,
+                                       nsIMsgRuleAction **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIMsgRuleAction> action;
+  rv = CreateRuleAction(aFilter, aActionType, getter_AddRefs(action));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsAutoCString targetFolder;
+  rv = GetDistributeTarget(aLine, targetFolder);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = action->SetTargetFolderUri(targetFolder);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  action.forget(_retval);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::CreateLeaveOrDeleteAction(const nsCString &aLine,
+                                          nsIMsgFilter *aFilter,
+                                          nsIMsgRuleAction **_retval)
+{
+  nsresult rv;
+  nsMsgRuleActionType actionType;
+  if (aLine.CharAt(3) == '0') {
+    actionType = nsMsgFilterAction::LeaveOnPop3Server;
+  } else if (aLine.CharAt(3) == '1') {
+    if (aLine.CharAt(5) == '1')
+      actionType = nsMsgFilterAction::Delete;
+    else
+      actionType = nsMsgFilterAction::DeleteFromPop3Server;
+  } else {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsIMsgRuleAction> action;
+  rv = CreateRuleAction(aFilter, actionType, getter_AddRefs(action));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  action.forget(_retval);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::SetRuleAction(const nsCString &aLine, nsIMsgFilter *aFilter)
+{
+  if (!aFilter || aLine.Length() < 4)
+    return NS_ERROR_FAILURE;
+
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIMsgRuleAction> action;
+  switch (aLine.CharAt(1)) {
+    case 'R': // Reply
+      rv = CreateResendAction(aLine,
+                              aFilter,
+                              nsMsgFilterAction::Reply,
+                              getter_AddRefs(action));
+      break;
+    case 'F': // Forward
+      rv = CreateResendAction(aLine,
+                              aFilter,
+                              nsMsgFilterAction::Forward,
+                              getter_AddRefs(action));
+      break;
+    case 'L': // Leave or delete
+      rv = CreateLeaveOrDeleteAction(aLine, aFilter, getter_AddRefs(action));
+      break;
+    case 'Y': // Copy
+      rv = CreateDistributeAction(aLine,
+                                  aFilter,
+                                  nsMsgFilterAction::CopyToFolder,
+                                  getter_AddRefs(action));
+      break;
+    case 'M': // Move
+      rv = CreateDistributeAction(aLine,
+                                  aFilter,
+                                  nsMsgFilterAction::MoveToFolder,
+                                  getter_AddRefs(action));
+      break;
+    case 'G': // Set flag
+      if (aLine.CharAt(3) == 'R') // Read
+        rv = CreateRuleAction(aFilter, nsMsgFilterAction::MarkRead, getter_AddRefs(action));
+      break;
+    default:
+      return NS_OK;
+  }
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (action) {
+    rv = aFilter->AppendAction(action);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::CreateFilter(nsIMsgFilter **_retval)
+{
+  NS_ENSURE_STATE(mServer);
+
+  nsCOMPtr <nsIMsgFilterList> filterList;
+  nsresult rv = mServer->GetFilterList(nullptr, getter_AddRefs(filterList));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgFilter> filter;
+  rv = filterList->CreateFilter(EmptyString(), getter_AddRefs(filter));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  filter->SetEnabled(true);
+  filter.forget(_retval);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::AppendFilter(nsIMsgFilter *aFilter)
+{
+  NS_ENSURE_STATE(mServer);
+
+  nsCOMPtr <nsIMsgFilterList> filterList;
+  nsresult rv = mServer->GetFilterList(nullptr, getter_AddRefs(filterList));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint32_t count;
+  rv = filterList->GetFilterCount(&count);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return filterList->InsertFilterAt(count, aFilter);
+}
+
+nsresult
+nsBeckyFilters::ParseFilterFile(nsIFile *aFile)
+{
+  nsresult rv;
+  nsCOMPtr<nsILineInputStream> lineStream;
+  rv = nsBeckyUtils::CreateLineInputStream(aFile, getter_AddRefs(lineStream));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more = true;
+  nsAutoCString line;
+
+  nsCOMPtr<nsIMsgFilter> filter;
+  while (NS_SUCCEEDED(rv) && more) {
+    rv = lineStream->ReadLine(line, &more);
+
+    switch (line.CharAt(0)) {
+      case ':':
+        if (line.EqualsLiteral(":Begin \"\"")) {
+          CreateFilter(getter_AddRefs(filter));
+        } else if (line.EqualsLiteral(":End \"\"")) {
+          if (filter)
+            AppendFilter(filter);
+          filter = nullptr;
+        }
+        break;
+      case '!':
+        SetRuleAction(line, filter);
+        break;
+      case '@':
+        SetSearchTerm(line, filter);
+        break;
+      case '$': // $X: disabled
+        if (StringBeginsWith(line, NS_LITERAL_CSTRING("$X")) && filter) {
+          filter->SetEnabled(false);
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyFilters::Import(char16_t **aError,
+                       bool *_retval)
+{
+  NS_ENSURE_ARG_POINTER(aError);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  *_retval = false;
+
+  nsresult rv;
+  if (!mLocation && NS_FAILED(GetDefaultFilterFile(getter_AddRefs(mLocation))))
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  rv = CollectServers();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = nsBeckyUtils::ConvertToUTF8File(mLocation, getter_AddRefs(mConvertedFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = ParseFilterFile(mConvertedFile);
+  if (NS_SUCCEEDED(rv))
+    *_retval = true;
+
+  RemoveConvertedFile();
+
+  return rv;
+}
+
+nsresult
+nsBeckyFilters::FindMessageFolder(const nsAString &aName,
+                                  nsIMsgFolder *aParentFolder,
+                                  nsIMsgFolder **_retval)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIMsgFolder> found;
+  rv = aParentFolder->GetChildNamed(aName, getter_AddRefs(found));
+  if (found) {
+    found.forget(_retval);
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> children;
+  rv = aParentFolder->GetSubFolders(getter_AddRefs(children));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more;
+  nsCOMPtr<nsISupports> entry;
+  while (NS_SUCCEEDED(children->HasMoreElements(&more)) && more) {
+    rv = children->GetNext(getter_AddRefs(entry));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIMsgFolder> child = do_QueryInterface(entry, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = FindMessageFolder(aName, child, getter_AddRefs(found));
+    if (found) {
+      found.forget(_retval);
+      return NS_OK;
+    }
+  }
+
+  return NS_MSG_ERROR_INVALID_FOLDER_NAME;
+}
+
+nsresult
+nsBeckyFilters::FindMessageFolderInServer(const nsAString &aName,
+                                          nsIMsgIncomingServer *aServer,
+                                          nsIMsgFolder **_retval)
+{
+  nsresult rv;
+  nsCOMPtr <nsIMsgFolder> rootFolder;
+  rv = aServer->GetRootMsgFolder(getter_AddRefs(rootFolder));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return FindMessageFolder(aName, rootFolder, _retval);
+}
+
+nsresult
+nsBeckyFilters::GetMessageFolder(const nsAString &aName,
+                                 nsIMsgFolder **_retval)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIMsgAccountManager> accountManager;
+  accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIArray> accounts;
+  rv = accountManager->GetAccounts(getter_AddRefs(accounts));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint32_t accountCount;
+  rv = accounts->GetLength(&accountCount);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgFolder> found;
+  for (uint32_t i = 0; i < accountCount; i++) {
+    nsCOMPtr<nsIMsgAccount> account(do_QueryElementAt(accounts, i));
+    if (!account)
+      continue;
+
+    nsCOMPtr<nsIMsgIncomingServer> server;
+    account->GetIncomingServer(getter_AddRefs(server));
+    if (!server)
+      continue;
+    FindMessageFolderInServer(aName, server, getter_AddRefs(found));
+    if (found)
+      break;
+  }
+
+  if (!found) {
+    nsCOMPtr<nsIMsgIncomingServer> server;
+    rv = accountManager->GetLocalFoldersServer(getter_AddRefs(server));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    FindMessageFolderInServer(aName, server, getter_AddRefs(found));
+  }
+
+  if (!found)
+    return NS_MSG_ERROR_INVALID_FOLDER_NAME;
+
+  found.forget(_retval);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyFilters::CollectServers()
+{
+  nsresult rv;
+  nsCOMPtr<nsIMsgAccountManager> accountManager;
+  accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgAccount> defaultAccount;
+  rv = accountManager->GetDefaultAccount(getter_AddRefs(defaultAccount));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgIncomingServer> server;
+  return defaultAccount->GetIncomingServer(getter_AddRefs(mServer));
+}
+
+nsresult
+nsBeckyFilters::RemoveConvertedFile()
+{
+  if (mConvertedFile) {
+    bool exists;
+    mConvertedFile->Exists(&exists);
+    if (exists)
+      mConvertedFile->Remove(false);
+    mConvertedFile = nullptr;
+  }
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyFilters.h
@@ -0,0 +1,76 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsBeckyFilters_h___
+#define nsBeckyFilters_h___
+
+#include "nsIImportFilters.h"
+#include "nsIFile.h"
+#include "nsIMsgIncomingServer.h"
+#include "nsMsgFilterCore.h"
+
+class nsIMsgFilter;
+class nsIMsgRuleAction;
+class nsCString;
+
+class nsBeckyFilters final : public nsIImportFilters
+{
+public:
+  nsBeckyFilters();
+  static nsresult Create(nsIImportFilters **aImport);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIIMPORTFILTERS
+
+private:
+  virtual ~nsBeckyFilters();
+
+  nsCOMPtr<nsIFile> mLocation;
+  nsCOMPtr<nsIMsgIncomingServer> mServer;
+  nsCOMPtr<nsIFile> mConvertedFile;
+
+  nsresult GetDefaultFilterFile(nsIFile **aFile);
+  nsresult ParseFilterFile(nsIFile *aFile);
+  nsresult ParseRuleLine(const nsCString &aLine,
+                         nsMsgSearchAttribValue *aSearchAttribute,
+                         nsMsgSearchOpValue *aSearchOperator,
+                         nsString &aSearchKeyword);
+  nsresult CollectServers();
+  nsresult FindMessageFolder(const nsAString& aName,
+                             nsIMsgFolder *aParantFolder,
+                             nsIMsgFolder **_retval);
+  nsresult FindMessageFolderInServer(const nsAString& aName,
+                                     nsIMsgIncomingServer *aServer,
+                                     nsIMsgFolder **_retval);
+  nsresult GetMessageFolder(const nsAString& aName, nsIMsgFolder **_retval);
+  nsresult GetActionTarget(const nsCString &aLine, nsCString &aTarget);
+  nsresult GetFolderNameFromTarget(const nsCString &aTarget, nsAString &aName);
+  nsresult GetDistributeTarget(const nsCString &aLine,
+                               nsCString &aTargetFolder);
+  nsresult GetResendTarget(const nsCString &aLine,
+                           nsCString &aTemplate,
+                           nsCString &aTargetAddress);
+  nsresult CreateRuleAction(nsIMsgFilter *aFilter,
+                            nsMsgRuleActionType actionType,
+                            nsIMsgRuleAction **_retval);
+  nsresult CreateDistributeAction(const nsCString &aLine,
+                                  nsIMsgFilter *aFilter,
+                                  const nsMsgRuleActionType &aActionType,
+                                  nsIMsgRuleAction **_retval);
+  nsresult CreateLeaveOrDeleteAction(const nsCString &aLine,
+                                     nsIMsgFilter *aFilter,
+                                     nsIMsgRuleAction **_retval);
+  nsresult CreateResendAction(const nsCString &aLine,
+                              nsIMsgFilter *aFilter,
+                              const nsMsgRuleActionType &aActionType,
+                              nsIMsgRuleAction **_retval);
+  nsresult CreateFilter(nsIMsgFilter **_retval);
+  nsresult AppendFilter(nsIMsgFilter *aFilter);
+  nsresult SetRuleAction(const nsCString &aLine, nsIMsgFilter *aFilter);
+  nsresult SetSearchTerm(const nsCString &aLine, nsIMsgFilter *aFilter);
+  nsresult RemoveConvertedFile();
+};
+
+#endif /* nsBeckyFilters_h___ */
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyImport.cpp
@@ -0,0 +1,169 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nscore.h"
+#include "nsIServiceManager.h"
+#include "nsIImportService.h"
+#include "nsIComponentManager.h"
+#include "nsIMemory.h"
+#include "nsIImportService.h"
+#include "nsIImportMail.h"
+#include "nsIImportMailboxDescriptor.h"
+#include "nsIImportGeneric.h"
+#include "nsIImportAddressBooks.h"
+#include "nsIImportABDescriptor.h"
+#include "nsIImportSettings.h"
+#include "nsIImportFilters.h"
+#include "nsIImportFieldMap.h"
+#include "nsXPCOM.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIOutputStream.h"
+#include "nsIAddrDatabase.h"
+#include "nsTextFormatter.h"
+#include "nsIStringBundle.h"
+#include "nsUnicharUtils.h"
+#include "nsIMsgTagService.h"
+#include "nsMsgBaseCID.h"
+#include "nsCOMPtr.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+
+#include "nsBeckyImport.h"
+#include "nsBeckyMail.h"
+#include "nsBeckyAddressBooks.h"
+#include "nsBeckySettings.h"
+#include "nsBeckyFilters.h"
+#include "nsBeckyStringBundle.h"
+
+nsBeckyImport::nsBeckyImport()
+{
+}
+
+nsBeckyImport::~nsBeckyImport()
+{
+}
+
+NS_IMPL_ISUPPORTS(nsBeckyImport, nsIImportModule)
+
+NS_IMETHODIMP
+nsBeckyImport::GetName(char16_t **aName)
+{
+  NS_ENSURE_ARG_POINTER(aName);
+  *aName =
+    nsBeckyStringBundle::GetStringByName(MOZ_UTF16("BeckyImportName"));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyImport::GetDescription(char16_t **aDescription)
+{
+  NS_ENSURE_ARG_POINTER(aDescription);
+  *aDescription =
+    nsBeckyStringBundle::GetStringByName(MOZ_UTF16("BeckyImportDescription"));
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyImport::GetSupports(char **aSupports)
+{
+  NS_ENSURE_ARG_POINTER(aSupports);
+  *aSupports = strdup(kBeckySupportsString);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyImport::GetSupportsUpgrade(bool *aUpgrade)
+{
+  NS_ENSURE_ARG_POINTER(aUpgrade);
+  *aUpgrade = true;
+  return NS_OK;
+}
+
+nsresult
+nsBeckyImport::GetMailImportInterface(nsISupports **aInterface)
+{
+  nsCOMPtr<nsIImportMail> importer;
+  nsresult rv = nsBeckyMail::Create(getter_AddRefs(importer));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIImportService> importService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIImportGeneric> generic;
+  rv = importService->CreateNewGenericMail(getter_AddRefs(generic));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  generic->SetData("mailInterface", importer);
+
+  nsString name;
+  name.Adopt(nsBeckyStringBundle::GetStringByName(MOZ_UTF16("BeckyImportName")));
+
+  nsCOMPtr<nsISupportsString> nameString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nameString->SetData(name);
+  generic->SetData("name", nameString);
+
+  return CallQueryInterface(generic, aInterface);
+}
+
+nsresult
+nsBeckyImport::GetAddressBookImportInterface(nsISupports **aInterface)
+{
+  nsresult rv;
+  nsCOMPtr<nsIImportAddressBooks> importer;
+  rv = nsBeckyAddressBooks::Create(getter_AddRefs(importer));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIImportService> importService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIImportGeneric> generic;
+  rv = importService->CreateNewGenericAddressBooks(getter_AddRefs(generic));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  generic->SetData("addressInterface", importer);
+  return CallQueryInterface(generic, aInterface);
+}
+
+nsresult
+nsBeckyImport::GetSettingsImportInterface(nsISupports **aInterface)
+{
+  nsresult rv;
+  nsCOMPtr<nsIImportSettings> importer;
+  rv = nsBeckySettings::Create(getter_AddRefs(importer));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return CallQueryInterface(importer, aInterface);
+}
+
+nsresult
+nsBeckyImport::GetFiltersImportInterface(nsISupports **aInterface)
+{
+  nsresult rv;
+  nsCOMPtr<nsIImportFilters> importer;
+  rv = nsBeckyFilters::Create(getter_AddRefs(importer));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return CallQueryInterface(importer, aInterface);
+}
+
+NS_IMETHODIMP
+nsBeckyImport::GetImportInterface(const char *aImportType, nsISupports **aInterface)
+{
+  NS_ENSURE_ARG_POINTER(aImportType);
+  NS_ENSURE_ARG_POINTER(aInterface);
+
+  *aInterface = nullptr;
+  if (!strcmp(aImportType, "mail"))
+    return GetMailImportInterface(aInterface);
+  if (!strcmp(aImportType, "addressbook"))
+    return GetAddressBookImportInterface(aInterface);
+  if (!strcmp(aImportType, "settings"))
+    return GetSettingsImportInterface(aInterface);
+  if (!strcmp(aImportType, "filters"))
+    return GetFiltersImportInterface(aInterface);
+
+  return NS_ERROR_NOT_AVAILABLE;
+}
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyImport.h
@@ -0,0 +1,36 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsBeckyImport_h___
+#define nsBeckyImport_h___
+
+#include "nsIImportModule.h"
+
+#define NS_BECKYIMPORT_CID          \
+{                                   \
+  0x7952a6cf, 0x2442,0x4c04,        \
+  {0x9f, 0x02, 0x15, 0x0b, 0x15, 0xa0, 0xa8, 0x41}}
+
+#define kBeckySupportsString NS_IMPORT_MAIL_STR "," NS_IMPORT_ADDRESS_STR "," NS_IMPORT_SETTINGS_STR "," NS_IMPORT_FILTERS_STR
+
+class nsBeckyImport final : public nsIImportModule
+{
+public:
+  nsBeckyImport();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIIMPORTMODULE
+
+private:
+  virtual ~nsBeckyImport();
+
+  nsresult GetMailImportInterface(nsISupports **aInterface);
+  nsresult GetAddressBookImportInterface(nsISupports **aInterface);
+  nsresult GetSettingsImportInterface(nsISupports **aInterface);
+  nsresult GetFiltersImportInterface(nsISupports **aInterface);
+
+};
+
+#endif /* nsBeckyImport_h___ */
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyMail.cpp
@@ -0,0 +1,642 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsString.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "nsIInputStream.h"
+#include "nsIOutputStream.h"
+#include "nsILineInputStream.h"
+#include "nsNetUtil.h"
+#include "nsIArray.h"
+#include "nsIImportService.h"
+#include "nsIImportMailboxDescriptor.h"
+#include "nsIMsgHdr.h"
+#include "nsIMsgFolder.h"
+#include "nsIMsgPluggableStore.h"
+#include "nsIMutableArray.h"
+#include "nsMsgUtils.h"
+#include "nsMsgLocalFolderHdrs.h"
+#include "nsMsgMessageFlags.h"
+#include "nsTArray.h"
+#include "nspr.h"
+#include "nsIStringBundle.h"
+#include "nsIEnumerator.h"
+#include "nsThreadUtils.h"
+
+#include "nsBeckyMail.h"
+#include "nsBeckyUtils.h"
+#include "nsBeckyStringBundle.h"
+
+#define FROM_LINE "From - Mon Jan 1 00:00:00 1965" MSG_LINEBREAK
+#define X_BECKY_STATUS_HEADER "X-Becky-Status"
+#define X_BECKY_INCLUDE_HEADER "X-Becky-Include"
+
+enum {
+  BECKY_STATUS_READ      = 1 << 0,
+  BECKY_STATUS_FORWARDED = 1 << 1,
+  BECKY_STATUS_REPLIED   = 1 << 2
+};
+
+NS_IMPL_ISUPPORTS(nsBeckyMail, nsIImportMail)
+
+nsresult
+nsBeckyMail::Create(nsIImportMail **aImport)
+{
+  NS_ENSURE_ARG_POINTER(aImport);
+
+  *aImport = new nsBeckyMail();
+
+  NS_ADDREF(*aImport);
+  return NS_OK;
+}
+
+nsBeckyMail::nsBeckyMail()
+: mReadBytes(0)
+{
+}
+
+nsBeckyMail::~nsBeckyMail()
+{
+}
+
+NS_IMETHODIMP
+nsBeckyMail::GetDefaultLocation(nsIFile **aLocation,
+                                bool *aFound,
+                                bool *aUserVerify)
+{
+  NS_ENSURE_ARG_POINTER(aFound);
+  NS_ENSURE_ARG_POINTER(aLocation);
+  NS_ENSURE_ARG_POINTER(aUserVerify);
+
+  *aLocation = nullptr;
+  *aUserVerify = true;
+  *aFound = false;
+  if (NS_SUCCEEDED(nsBeckyUtils::GetDefaultMailboxDirectory(aLocation)))
+    *aFound = true;
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyMail::CreateMailboxDescriptor(nsIImportMailboxDescriptor **aDescriptor)
+{
+  nsresult rv;
+  nsCOMPtr<nsIImportService> importService;
+  importService = do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return importService->CreateNewMailboxDescriptor(aDescriptor);
+}
+
+nsresult
+nsBeckyMail::GetMailboxName(nsIFile *aMailbox, nsAString &aName)
+{
+  nsCOMPtr<nsIFile> iniFile;
+  nsBeckyUtils::GetMailboxINIFile(aMailbox, getter_AddRefs(iniFile));
+  if (iniFile) {
+    nsCOMPtr<nsIFile> convertedFile;
+    nsBeckyUtils::ConvertToUTF8File(iniFile, getter_AddRefs(convertedFile));
+    if (convertedFile) {
+      nsAutoCString utf8Name;
+      nsBeckyUtils::GetMailboxNameFromINIFile(convertedFile, utf8Name);
+      convertedFile->Remove(false);
+      CopyUTF8toUTF16(utf8Name, aName);
+    }
+  }
+
+  if (aName.IsEmpty()) {
+    nsAutoString name;
+    aMailbox->GetLeafName(name);
+    name.Trim("!", true, false);
+    aName.Assign(name);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyMail::AppendMailboxDescriptor(nsIFile *aEntry,
+                                     const nsString &aName,
+                                     uint32_t aDepth,
+                                     nsIMutableArray *aCollected)
+{
+  nsresult rv;
+  nsCOMPtr<nsIImportMailboxDescriptor> descriptor;
+  rv = CreateMailboxDescriptor(getter_AddRefs(descriptor));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  int64_t size;
+  rv = aEntry->GetFileSize(&size);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = descriptor->SetSize(size);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = descriptor->SetDisplayName(aName.get());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIFile> mailboxFile;
+  rv = descriptor->GetFile(getter_AddRefs(mailboxFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  descriptor->SetDepth(aDepth);
+
+  mailboxFile->InitWithFile(aEntry);
+  aCollected->AppendElement(descriptor, false);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyMail::CollectMailboxesInFolderListFile(nsIFile *aListFile,
+                                              uint32_t aDepth,
+                                              nsIMutableArray *aCollected)
+{
+  nsresult rv;
+  nsCOMPtr<nsILineInputStream> lineStream;
+  rv = nsBeckyUtils::CreateLineInputStream(aListFile,
+                                           getter_AddRefs(lineStream));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIFile> parent;
+  rv = aListFile->GetParent(getter_AddRefs(parent));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more = true;
+  nsAutoCString folderName;
+  bool isEmpty = true;
+  while (more && NS_SUCCEEDED(rv)) {
+    rv = lineStream->ReadLine(folderName, &more);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (folderName.IsEmpty())
+      continue;
+
+    nsCOMPtr<nsIFile> folder;
+    rv = parent->Clone(getter_AddRefs(folder));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = folder->AppendNative(folderName);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    isEmpty = false;
+    rv = CollectMailboxesInDirectory(folder, aDepth + 1, aCollected);
+  }
+
+  return isEmpty ? NS_ERROR_FILE_NOT_FOUND : NS_OK;
+}
+
+nsresult
+nsBeckyMail::CollectMailboxesInDirectory(nsIFile *aDirectory,
+                                         uint32_t aDepth,
+                                         nsIMutableArray *aCollected)
+{
+  nsAutoString mailboxName;
+  nsresult rv = GetMailboxName(aDirectory, mailboxName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aDepth != 0)
+    AppendMailboxDescriptor(aDirectory, mailboxName, aDepth, aCollected);
+
+  nsCOMPtr<nsIFile> folderListFile;
+  rv = nsBeckyUtils::GetFolderListFile(aDirectory, getter_AddRefs(folderListFile));
+  bool folderListExists = false;
+
+  if (NS_SUCCEEDED(rv)) {
+    rv = CollectMailboxesInFolderListFile(folderListFile, aDepth, aCollected);
+    folderListExists = true;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
+    nsCOMPtr<nsISupports> entry;
+    rv = entries->GetNext(getter_AddRefs(entry));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIFile> file = do_QueryInterface(entry, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsAutoString name;
+    rv = file->GetLeafName(name);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (StringEndsWith(name, NS_LITERAL_STRING(".bmf"))) {
+      AppendMailboxDescriptor(file, mailboxName, aDepth, aCollected);
+    }
+
+    // The Folder.lst file is not created if there is only one sub folder,
+    // so we need to find the sub folder by our hands.
+    // The folder name does not begin with # or ! maybe. Yes, maybe...
+    if (!folderListExists) {
+      if (StringBeginsWith(name, NS_LITERAL_STRING("#")) ||
+          StringBeginsWith(name, NS_LITERAL_STRING("!")))
+        continue;
+
+      bool isDirectory = false;
+      rv = file->IsDirectory(&isDirectory);
+      if (isDirectory) {
+        CollectMailboxesInDirectory(file, aDepth + 1, aCollected);
+        continue;
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyMail::FindMailboxes(nsIFile *aLocation, nsIArray **_retval)
+{
+  NS_ENSURE_ARG_POINTER(aLocation);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsresult rv;
+  nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = CollectMailboxesInDirectory(aLocation, 0, array);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  array.forget(_retval);
+
+  return NS_OK;
+}
+
+static nsresult
+GetBeckyStatusValue(const nsCString &aHeader, nsACString &aValue)
+{
+  int32_t valueStartPosition;
+
+  valueStartPosition = aHeader.FindChar(':');
+  if (valueStartPosition < 0)
+    return NS_ERROR_UNEXPECTED;
+
+  valueStartPosition++;
+
+  int32_t commaPosition = aHeader.FindChar(',', valueStartPosition);
+  if (commaPosition < 0)
+    return NS_ERROR_UNEXPECTED;
+
+  nsAutoCString value(Substring(aHeader,
+                                valueStartPosition,
+                                commaPosition - valueStartPosition));
+  value.Trim(" \t");
+
+  aValue.Assign(value);
+
+  return NS_OK;
+}
+
+static nsresult
+GetBeckyIncludeValue(const nsCString &aHeader, nsACString &aValue)
+{
+  int32_t valueStartPosition;
+
+  valueStartPosition = aHeader.FindChar(':');
+  if (valueStartPosition < 0)
+    return NS_ERROR_FAILURE;
+
+  valueStartPosition++;
+  nsAutoCString value(Substring(aHeader, valueStartPosition));
+  value.Trim(" \t");
+
+  aValue.Assign(value);
+
+  return NS_OK;
+}
+
+static bool
+ConvertBeckyStatusToMozillaStatus(const nsCString &aHeader,
+                                  nsMsgMessageFlagType *aMozillaStatusFlag)
+{
+  nsresult rv;
+  nsAutoCString statusString;
+  rv = GetBeckyStatusValue(aHeader, statusString);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsresult errorCode;
+  uint32_t beckyStatusFlag = static_cast<uint32_t>(statusString.ToInteger(&errorCode, 16));
+  if (NS_FAILED(errorCode))
+    return false;
+
+  if (beckyStatusFlag & BECKY_STATUS_READ)
+    *aMozillaStatusFlag |= nsMsgMessageFlags::Read;
+  if (beckyStatusFlag & BECKY_STATUS_FORWARDED)
+    *aMozillaStatusFlag |= nsMsgMessageFlags::Forwarded;
+  if (beckyStatusFlag & BECKY_STATUS_REPLIED)
+    *aMozillaStatusFlag |= nsMsgMessageFlags::Replied;
+
+  return true;
+}
+
+static inline bool
+CheckHeaderKey(const nsCString &aHeader, const char *aKeyString)
+{
+  nsAutoCString key(StringHead(aHeader, aHeader.FindChar(':')));
+  key.Trim(" \t");
+  return key.Equals(aKeyString);
+}
+
+static inline bool
+IsBeckyStatusHeader(const nsCString &aHeader)
+{
+  return CheckHeaderKey(aHeader, X_BECKY_STATUS_HEADER);
+}
+
+static inline bool
+IsBeckyIncludeLine(const nsCString &aLine)
+{
+  return CheckHeaderKey(aLine, X_BECKY_INCLUDE_HEADER);
+}
+
+static inline bool
+IsEndOfHeaders(const nsCString &aLine)
+{
+  return aLine.IsEmpty();
+}
+
+static inline bool
+IsEndOfMessage(const nsCString &aLine)
+{
+  return aLine.Equals(".");
+}
+
+class ImportMessageRunnable: public nsRunnable
+{
+public:
+  ImportMessageRunnable(nsIFile *aMessageFile,
+                        nsIMsgFolder *aFolder);
+  NS_DECL_NSIRUNNABLE
+private:
+  nsresult WriteHeaders(nsCString &aHeaders, nsIOutputStream *aOutputStream);
+  nsresult HandleHeaderLine(const nsCString &aHeaderLine, nsACString &aHeaders);
+  nsresult GetAttachmentFile(nsIFile *aMailboxFile,
+                             const nsCString &aHeader,
+                             nsIFile **_retval);
+  nsresult WriteAttachmentFile(nsIFile *aMailboxFile,
+                               const nsCString &aHeader,
+                               nsIOutputStream *aOutputStream);
+
+  nsCOMPtr<nsIFile> mMessageFile;
+  nsCOMPtr<nsIMsgFolder> mFolder;
+};
+
+ImportMessageRunnable::ImportMessageRunnable(nsIFile *aMessageFile,
+                                             nsIMsgFolder *aFolder) :
+  mMessageFile(aMessageFile), mFolder(aFolder)
+{
+}
+
+nsresult
+ImportMessageRunnable::WriteHeaders(nsCString &aHeaders,
+                                    nsIOutputStream *aOutputStream)
+{
+  nsresult rv;
+  uint32_t writtenBytes = 0;
+
+  rv = aOutputStream->Write(FROM_LINE, strlen(FROM_LINE), &writtenBytes);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aOutputStream->Write(aHeaders.get(), aHeaders.Length(), &writtenBytes);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aOutputStream->Write(MSG_LINEBREAK, strlen(MSG_LINEBREAK), &writtenBytes);
+  NS_ENSURE_SUCCESS(rv, rv);
+  aHeaders.Truncate();
+
+  return NS_OK;
+}
+
+nsresult
+ImportMessageRunnable::HandleHeaderLine(const nsCString &aHeaderLine,
+                                        nsACString &aHeaders)
+{
+  aHeaders.Append(aHeaderLine);
+  aHeaders.AppendLiteral(MSG_LINEBREAK);
+
+  nsMsgMessageFlagType flag = 0;
+  if (IsBeckyStatusHeader(aHeaderLine) &&
+      ConvertBeckyStatusToMozillaStatus(aHeaderLine, &flag)) {
+    char *statusLine;
+    statusLine = PR_smprintf(X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, flag);
+    aHeaders.Append(statusLine);
+    PR_smprintf_free(statusLine);
+    aHeaders.AppendLiteral(X_MOZILLA_KEYWORDS);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+ImportMessageRunnable::GetAttachmentFile(nsIFile *aMailboxFile,
+                                         const nsCString &aHeader,
+                                         nsIFile **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> attachmentFile;
+
+  rv = aMailboxFile->Clone(getter_AddRefs(attachmentFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = attachmentFile->Append(NS_LITERAL_STRING("#Attach"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString nativeAttachmentPath;
+  rv = GetBeckyIncludeValue(aHeader, nativeAttachmentPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = attachmentFile->AppendRelativeNativePath(nativeAttachmentPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists = false;
+  attachmentFile->Exists(&exists);
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  attachmentFile.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+ImportMessageRunnable::WriteAttachmentFile(nsIFile *aMailboxFile,
+                                           const nsCString &aHeader,
+                                           nsIOutputStream *aOutputStream)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> parentDirectory;
+  rv = aMailboxFile->GetParent(getter_AddRefs(parentDirectory));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIFile> attachmentFile;
+  rv = GetAttachmentFile(parentDirectory,
+                         aHeader,
+                         getter_AddRefs(attachmentFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIInputStream> inputStream;
+  rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream),
+                                  attachmentFile);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  char buffer[4096];
+  uint32_t readBytes = 0;
+  uint32_t writtenBytes = 0;
+  rv = aOutputStream->Write(MSG_LINEBREAK, strlen(MSG_LINEBREAK), &writtenBytes);
+  while (NS_SUCCEEDED(inputStream->Read(buffer, sizeof(buffer), &readBytes)) &&
+         readBytes > 0) {
+    rv = aOutputStream->Write(buffer, readBytes, &writtenBytes);
+    if (NS_FAILED(rv))
+      break;
+  }
+
+  return rv;
+}
+
+NS_IMETHODIMP ImportMessageRunnable::Run()
+{
+  nsCOMPtr<nsIMsgPluggableStore> msgStore;
+  nsresult rv = mFolder->GetMsgStore(getter_AddRefs(msgStore));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsILineInputStream> lineStream;
+  rv = nsBeckyUtils::CreateLineInputStream(mMessageFile,
+                                           getter_AddRefs(lineStream));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool reusable;
+  nsCOMPtr<nsIMsgDBHdr> msgHdr;
+  nsCOMPtr<nsIOutputStream> outputStream;
+  rv = msgStore->GetNewMsgOutputStream(mFolder, getter_AddRefs(msgHdr), &reusable,
+                                       getter_AddRefs(outputStream));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool inHeader = true;
+  bool more = true;
+  nsAutoCString headers;
+  while (NS_SUCCEEDED(rv) && more) {
+    nsAutoCString line;
+    rv = lineStream->ReadLine(line, &more);
+    if (NS_FAILED(rv))
+      break;
+
+    if (inHeader) {
+      if (IsEndOfHeaders(line)) {
+        inHeader = false;
+        rv = WriteHeaders(headers, outputStream);
+      } else {
+        rv = HandleHeaderLine(line, headers);
+      }
+    } else if (IsEndOfMessage(line)) {
+      inHeader = true;
+      rv = msgStore->FinishNewMessage(outputStream, msgHdr);
+      if (!reusable)
+        outputStream->Close();
+      rv = msgStore->GetNewMsgOutputStream(mFolder, getter_AddRefs(msgHdr), &reusable,
+                                           getter_AddRefs(outputStream));
+    } else if (IsBeckyIncludeLine(line)) {
+      rv = WriteAttachmentFile(mMessageFile, line, outputStream);
+    } else {
+      uint32_t writtenBytes = 0;
+      if (StringBeginsWith(line, NS_LITERAL_CSTRING("..")))
+        line.Cut(0, 1);
+      else if (CheckHeaderKey(line, "From"))
+        line.Insert('>', 0);
+
+      line.AppendLiteral(MSG_LINEBREAK);
+      rv = outputStream->Write(line.get(), line.Length(), &writtenBytes);
+    }
+  }
+
+  if (outputStream) {
+    if (NS_FAILED(rv))
+      msgStore->DiscardNewMessage(outputStream, msgHdr);
+    outputStream->Close();
+  }
+
+  return rv;
+}
+
+static
+nsresult ProxyImportMessage(nsIFile *aMessageFile,
+                            nsIMsgFolder *aFolder)
+{
+  RefPtr<ImportMessageRunnable> importMessage =
+    new ImportMessageRunnable(aMessageFile, aFolder);
+  return NS_DispatchToMainThread(importMessage, NS_DISPATCH_SYNC);
+}
+
+nsresult
+nsBeckyMail::ImportMailFile(nsIFile *aMailFile,
+                            nsIMsgFolder *aDestination)
+{
+  int64_t size;
+  aMailFile->GetFileSize(&size);
+  if (size == 0)
+    return NS_OK;
+
+  return ProxyImportMessage(aMailFile, aDestination);
+}
+
+NS_IMETHODIMP
+nsBeckyMail::ImportMailbox(nsIImportMailboxDescriptor *aSource,
+                           nsIMsgFolder *aDestination,
+                           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);
+
+  mReadBytes = 0;
+
+  nsresult rv;
+  nsCOMPtr<nsIFile> mailboxFolder;
+  rv = aSource->GetFile(getter_AddRefs(mailboxFolder));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = ImportMailFile(mailboxFolder, aDestination);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  uint32_t finalSize;
+  aSource->GetSize(&finalSize);
+  mReadBytes = finalSize;
+
+  nsAutoString name;
+  aSource->GetDisplayName(getter_Copies(name));
+
+  nsAutoString successMessage;
+  const char16_t *format = { name.get() };
+  rv =
+      nsBeckyStringBundle::FormatStringFromName(MOZ_UTF16("BeckyImportMailboxSuccess"),
+                                                &format,
+                                                1,
+                                                getter_Copies(successMessage));
+  successMessage.AppendLiteral("\n");
+  *aSuccessLog = ToNewUnicode(successMessage);
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsBeckyMail::GetImportProgress(uint32_t *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+  *_retval = mReadBytes;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckyMail::TranslateFolderName(const nsAString & aFolderName,
+                                 nsAString & _retval)
+{
+  return nsBeckyUtils::TranslateFolderName(aFolderName, _retval);
+}
+
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyMail.h
@@ -0,0 +1,45 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsBeckyMail_h___
+#define nsBeckyMail_h___
+
+#include "nsIImportMail.h"
+
+class nsIFile;
+class nsIMutableArray;
+class nsIMsgFolder;
+
+class nsBeckyMail final : public nsIImportMail
+{
+public:
+  nsBeckyMail();
+  static nsresult Create(nsIImportMail **aImport);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIIMPORTMAIL
+
+private:
+  virtual ~nsBeckyMail();
+
+  uint32_t mReadBytes;
+
+  nsresult CollectMailboxesInDirectory(nsIFile *aDirectory,
+                                       uint32_t aDepth,
+                                       nsIMutableArray *aCollected);
+  nsresult CollectMailboxesInFolderListFile(nsIFile *aListFile,
+                                            uint32_t aDepth,
+                                            nsIMutableArray *aCollected);
+  nsresult AppendMailboxDescriptor(nsIFile *aEntry,
+                                   const nsString &aName,
+                                   uint32_t aDepth,
+                                   nsIMutableArray *aCollected);
+  nsresult ImportMailFile(nsIFile *aMailFile,
+                          nsIMsgFolder *aDestination);
+  nsresult CreateMailboxDescriptor(nsIImportMailboxDescriptor **aDescriptor);
+  nsresult GetMailboxName(nsIFile *aMailbox, nsAString &aName);
+};
+
+#endif /* nsBeckyMail_h___ */
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckySettings.cpp
@@ -0,0 +1,471 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsMsgBaseCID.h"
+#include "nsMsgCompCID.h"
+#include "nsIMsgAccountManager.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIINIParser.h"
+#include "nsISmtpService.h"
+#include "nsISmtpServer.h"
+#include "nsIPop3IncomingServer.h"
+#include "nsIStringEnumerator.h"
+#include "nsIInputStream.h"
+#include "nsIOutputStream.h"
+#include "nsILineInputStream.h"
+#include "nsNetUtil.h"
+#include "nsString.h"
+#include "msgCore.h"
+#include "nsIStringBundle.h"
+
+#include "nsBeckySettings.h"
+#include "nsBeckyStringBundle.h"
+#include "nsBeckyUtils.h"
+
+NS_IMPL_ISUPPORTS(nsBeckySettings, nsIImportSettings)
+
+nsresult
+nsBeckySettings::Create(nsIImportSettings **aImport)
+{
+  NS_ENSURE_ARG_POINTER(aImport);
+
+  *aImport = new nsBeckySettings();
+
+  NS_ADDREF(*aImport);
+  return NS_OK;
+}
+
+nsBeckySettings::nsBeckySettings()
+{
+}
+
+nsBeckySettings::~nsBeckySettings()
+{
+}
+
+NS_IMETHODIMP
+nsBeckySettings::AutoLocate(char16_t **aDescription,
+                            nsIFile **aLocation,
+                            bool *_retval)
+{
+  NS_ENSURE_ARG_POINTER(aDescription);
+  NS_ENSURE_ARG_POINTER(aLocation);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  *aDescription =
+    nsBeckyStringBundle::GetStringByName(MOZ_UTF16("BeckyImportName"));
+  *aLocation = nullptr;
+  *_retval = false;
+
+  nsCOMPtr<nsIFile> location;
+  nsresult rv = nsBeckyUtils::GetDefaultMailboxINIFile(getter_AddRefs(location));
+  if (NS_FAILED(rv))
+    location = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+  else
+    *_retval = true;
+
+  location.forget(aLocation);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsBeckySettings::SetLocation(nsIFile *aLocation)
+{
+  mLocation = aLocation;
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::CreateParser()
+{
+  if (!mLocation) {
+    nsresult rv = nsBeckyUtils::GetDefaultMailboxINIFile(getter_AddRefs(mLocation));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // nsIINIParser accepts only UTF-8 encoding, so we need to convert the file
+  // first.
+  nsresult rv;
+  rv = nsBeckyUtils::ConvertToUTF8File(mLocation, getter_AddRefs(mConvertedFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return nsBeckyUtils::CreateINIParserForFile(mConvertedFile,
+                                              getter_AddRefs(mParser));
+}
+
+nsresult
+nsBeckySettings::CreateSmtpServer(const nsCString &aUserName,
+                                  const nsCString &aServerName,
+                                  nsISmtpServer **aServer,
+                                  bool *existing)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsISmtpService> smtpService = do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsISmtpServer> server;
+  rv = smtpService->FindServer(aUserName.get(),
+                               aServerName.get(),
+                               getter_AddRefs(server));
+
+  if (NS_FAILED(rv) || !server) {
+    rv = smtpService->CreateServer(getter_AddRefs(server));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    server->SetHostname(aServerName);
+    server->SetUsername(aUserName);
+    *existing = false;
+  } else {
+    *existing = true;
+  }
+
+  server.forget(aServer);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::CreateIncomingServer(const nsCString &aUserName,
+                                      const nsCString &aServerName,
+                                      const nsCString &aProtocol,
+                                      nsIMsgIncomingServer **aServer)
+{
+  nsresult rv;
+  nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgIncomingServer> incomingServer;
+  rv = accountManager->FindServer(aUserName,
+                                  aServerName,
+                                  aProtocol,
+                                  getter_AddRefs(incomingServer));
+
+  if (NS_FAILED(rv) || !incomingServer) {
+    rv = accountManager->CreateIncomingServer(aUserName,
+                                              aServerName,
+                                              aProtocol,
+                                              getter_AddRefs(incomingServer));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  incomingServer.forget(aServer);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::SetupSmtpServer(nsISmtpServer **aServer)
+{
+  nsresult rv;
+  nsAutoCString userName, serverName;
+
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("SMTPServer"),
+                     serverName);
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("UserID"),
+                     userName);
+
+  nsCOMPtr<nsISmtpServer> server;
+  bool existing = false;
+  rv = CreateSmtpServer(userName, serverName, getter_AddRefs(server), &existing);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If we already have an existing server, do not touch it's settings.
+  if (existing) {
+    server.forget(aServer);
+    return NS_OK;
+  }
+
+  nsAutoCString value;
+  rv = mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                          NS_LITERAL_CSTRING("SMTPPort"),
+                          value);
+  int32_t port = 25;
+  if (NS_SUCCEEDED(rv)) {
+    nsresult errorCode;
+    port = value.ToInteger(&errorCode, 10);
+  }
+  server->SetPort(port);
+
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("SSLSMTP"),
+                     value);
+  if (value.Equals("1"))
+    server->SetSocketType(nsMsgSocketType::SSL);
+
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("SMTPAUTH"),
+                     value);
+  if (value.Equals("1")) {
+    mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                       NS_LITERAL_CSTRING("SMTPAUTHMODE"),
+                       value);
+    nsMsgAuthMethodValue authMethod = nsMsgAuthMethod::none;
+    if (value.Equals("1")) {
+      authMethod = nsMsgAuthMethod::passwordEncrypted;
+    } else if (value.Equals("2") ||
+               value.Equals("4") ||
+               value.Equals("6")) {
+      authMethod = nsMsgAuthMethod::passwordCleartext;
+    } else {
+      authMethod = nsMsgAuthMethod::anything;
+    }
+    server->SetAuthMethod(authMethod);
+  }
+
+  server.forget(aServer);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::SetPop3ServerProperties(nsIMsgIncomingServer *aServer)
+{
+  nsCOMPtr<nsIPop3IncomingServer> pop3Server = do_QueryInterface(aServer);
+
+  nsAutoCString value;
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("POP3Auth"),
+                     value); // 0: plain, 1: APOP, 2: CRAM-MD5, 3: NTLM
+  nsMsgAuthMethodValue authMethod;
+  if (value.IsEmpty() || value.Equals("0")) {
+    authMethod = nsMsgAuthMethod::passwordCleartext;
+  } else if (value.Equals("1")) {
+    authMethod = nsMsgAuthMethod::old;
+  } else if (value.Equals("2")) {
+    authMethod = nsMsgAuthMethod::passwordEncrypted;
+  } else if (value.Equals("3")) {
+    authMethod = nsMsgAuthMethod::NTLM;
+  } else {
+    authMethod = nsMsgAuthMethod::none;
+  }
+  aServer->SetAuthMethod(authMethod);
+
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("LeaveServer"),
+                     value);
+  if (value.Equals("1")) {
+    pop3Server->SetLeaveMessagesOnServer(true);
+    nsresult rv = mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                                     NS_LITERAL_CSTRING("KeepDays"),
+                                     value);
+    if (NS_FAILED(rv))
+      return NS_OK;
+
+    nsresult errorCode;
+    int32_t leftDays = value.ToInteger(&errorCode, 10);
+    if (NS_SUCCEEDED(errorCode)) {
+      pop3Server->SetNumDaysToLeaveOnServer(leftDays);
+      pop3Server->SetDeleteByAgeFromServer(true);
+    }
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::SetupIncomingServer(nsIMsgIncomingServer **aServer)
+{
+  nsAutoCString value;
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("Protocol"),
+                     value);
+  nsCString protocol;
+  if (value.Equals("1")) {
+    protocol = NS_LITERAL_CSTRING("imap");
+  } else {
+    protocol = NS_LITERAL_CSTRING("pop3");
+  }
+
+  nsAutoCString userName, serverName;
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("MailServer"),
+                     serverName);
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("UserID"),
+                     userName);
+
+  nsresult rv;
+  nsCOMPtr<nsIMsgIncomingServer> server;
+  rv = CreateIncomingServer(userName, serverName, protocol, getter_AddRefs(server));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool isSecure = false;
+  int32_t port = 0;
+  nsresult errorCode;
+  if (protocol.EqualsLiteral("pop3")) {
+    SetPop3ServerProperties(server);
+    rv = mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                            NS_LITERAL_CSTRING("POP3Port"),
+                            value);
+    if (NS_SUCCEEDED(rv))
+      port = value.ToInteger(&errorCode, 10);
+    else
+      port = 110;
+    mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                       NS_LITERAL_CSTRING("SSLPOP"),
+                       value);
+    if (value.Equals("1"))
+      isSecure = true;
+  } else if (protocol.EqualsLiteral("imap")) {
+    rv = mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                            NS_LITERAL_CSTRING("IMAP4Port"),
+                            value);
+    if (NS_SUCCEEDED(rv))
+      port = value.ToInteger(&errorCode, 10);
+    else
+      port = 143;
+    mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                       NS_LITERAL_CSTRING("SSLIMAP"),
+                       value);
+    if (value.Equals("1"))
+      isSecure = true;
+  }
+
+  server->SetPort(port);
+  if (isSecure)
+    server->SetSocketType(nsMsgSocketType::SSL);
+
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("CheckInt"),
+                     value);
+  if (value.Equals("1"))
+    server->SetDoBiff(true);
+  rv = mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                          NS_LITERAL_CSTRING("CheckEvery"),
+                          value);
+  if (NS_SUCCEEDED(rv)) {
+    int32_t minutes = value.ToInteger(&errorCode, 10);
+    if (NS_SUCCEEDED(errorCode))
+      server->SetBiffMinutes(minutes);
+  }
+
+  server.forget(aServer);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::CreateIdentity(nsIMsgIdentity **aIdentity)
+{
+  nsAutoCString email, fullName, identityName, bccAddress;
+
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("Name"),
+                     identityName);
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("YourName"),
+                     fullName);
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("MailAddress"),
+                     email);
+  mParser->GetString(NS_LITERAL_CSTRING("Account"),
+                     NS_LITERAL_CSTRING("PermBcc"),
+                     bccAddress);
+
+  nsresult rv;
+  nsCOMPtr<nsIMsgAccountManager> accountManager =
+    do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgIdentity> identity;
+  rv = accountManager->CreateIdentity(getter_AddRefs(identity));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  identity->SetIdentityName(NS_ConvertUTF8toUTF16(identityName));
+  identity->SetFullName(NS_ConvertUTF8toUTF16(fullName));
+  identity->SetEmail(email);
+  if (!bccAddress.IsEmpty()) {
+    identity->SetDoBcc(true);
+    identity->SetDoBccList(bccAddress);
+  }
+
+  identity.forget(aIdentity);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::CreateAccount(nsIMsgIdentity *aIdentity,
+                               nsIMsgIncomingServer *aIncomingServer,
+                               nsIMsgAccount **aAccount)
+{
+  nsresult rv;
+  nsCOMPtr<nsIMsgAccountManager> accountManager =
+    do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIMsgAccount> account;
+  rv = accountManager->CreateAccount(getter_AddRefs(account));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = account->AddIdentity(aIdentity);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = account->SetIncomingServer(aIncomingServer);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  account.forget(aAccount);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckySettings::RemoveConvertedFile()
+{
+  if (mConvertedFile) {
+    bool exists;
+    mConvertedFile->Exists(&exists);
+    if (exists)
+      mConvertedFile->Remove(false);
+    mConvertedFile = nullptr;
+  }
+  return NS_OK;
+}
+
+#define NS_RETURN_IF_FAILED_WITH_REMOVE_CONVERTED_FILE(expr, rv) \
+  if (NS_FAILED(expr)) {                                         \
+    RemoveConvertedFile();                                       \
+    return rv;                                                   \
+  }
+
+NS_IMETHODIMP
+nsBeckySettings::Import(nsIMsgAccount **aLocalMailAccount,
+                        bool *_retval)
+{
+  NS_ENSURE_ARG_POINTER(aLocalMailAccount);
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsresult rv = CreateParser();
+  NS_RETURN_IF_FAILED_WITH_REMOVE_CONVERTED_FILE(rv, rv);
+
+  nsCOMPtr<nsIMsgIncomingServer> incomingServer;
+  rv = SetupIncomingServer(getter_AddRefs(incomingServer));
+  NS_RETURN_IF_FAILED_WITH_REMOVE_CONVERTED_FILE(rv, rv);
+
+  nsCOMPtr<nsISmtpServer> smtpServer;
+  rv = SetupSmtpServer(getter_AddRefs(smtpServer));
+  NS_RETURN_IF_FAILED_WITH_REMOVE_CONVERTED_FILE(rv, rv);
+
+  nsCOMPtr<nsIMsgIdentity> identity;
+  rv = CreateIdentity(getter_AddRefs(identity));
+  NS_RETURN_IF_FAILED_WITH_REMOVE_CONVERTED_FILE(rv, rv);
+
+  nsAutoCString smtpKey;
+  smtpServer->GetKey(getter_Copies(smtpKey));
+  identity->SetSmtpServerKey(smtpKey);
+
+  nsCOMPtr<nsIMsgAccount> account;
+  rv = CreateAccount(identity, incomingServer, getter_AddRefs(account));
+  NS_RETURN_IF_FAILED_WITH_REMOVE_CONVERTED_FILE(rv, rv);
+
+  RemoveConvertedFile();
+  if (aLocalMailAccount)
+    account.forget(aLocalMailAccount);
+  *_retval = true;
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckySettings.h
@@ -0,0 +1,52 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsBeckySettings_h___
+#define nsBeckySettings_h___
+
+#include "nsIImportSettings.h"
+#include "nsIFile.h"
+#include "nsIINIParser.h"
+
+class nsIMsgIncomingServer;
+class nsIMsgIdentity;
+class nsISmtpServer;
+
+class nsBeckySettings final : public nsIImportSettings
+{
+public:
+  nsBeckySettings();
+  static nsresult Create(nsIImportSettings **aImport);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIIMPORTSETTINGS
+
+private:
+  virtual ~nsBeckySettings();
+
+  nsCOMPtr<nsIFile> mLocation;
+  nsCOMPtr<nsIFile> mConvertedFile;
+  nsCOMPtr<nsIINIParser> mParser;
+
+  nsresult CreateParser();
+  nsresult CreateIdentity(nsIMsgIdentity **aIdentity);
+  nsresult CreateAccount(nsIMsgIdentity *aIdentity,
+                         nsIMsgIncomingServer *aIncomingServer,
+                         nsIMsgAccount **aAccount);
+  nsresult CreateSmtpServer(const nsCString &aUserName,
+                            const nsCString &aServerName,
+                            nsISmtpServer **aServer,
+                            bool *existing);
+  nsresult CreateIncomingServer(const nsCString &aUserName,
+                                const nsCString &aServerName,
+                                const nsCString &aProtocol,
+                                nsIMsgIncomingServer **aServer);
+  nsresult SetupIncomingServer(nsIMsgIncomingServer **aServer);
+  nsresult SetupSmtpServer(nsISmtpServer **aServer);
+  nsresult SetPop3ServerProperties(nsIMsgIncomingServer *aServer);
+  nsresult RemoveConvertedFile();
+};
+
+#endif /* nsBeckySettings_h___ */
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyStringBundle.cpp
@@ -0,0 +1,74 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "prprf.h"
+#include "prmem.h"
+#include "nsCOMPtr.h"
+#include "nsIStringBundle.h"
+#include "nsIServiceManager.h"
+#include "nsIURI.h"
+#include "nsServiceManagerUtils.h"
+#include "nsXPCOMCIDInternal.h"
+
+#include "nsBeckyStringBundle.h"
+
+#define BECKY_MESSAGES_URL "chrome://messenger/locale/beckyImportMsgs.properties"
+
+nsIStringBundle *nsBeckyStringBundle::mBundle = nullptr;
+
+nsIStringBundle *
+nsBeckyStringBundle::GetStringBundle(void)
+{
+  if (mBundle)
+    return mBundle;
+
+  nsresult rv;
+  nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
+  if (NS_SUCCEEDED(rv) && bundleService)
+    rv = bundleService->CreateBundle(BECKY_MESSAGES_URL, &mBundle);
+
+  return mBundle;
+}
+
+void
+nsBeckyStringBundle::EnsureStringBundle(void)
+{
+  if (!mBundle)
+    (void) GetStringBundle();
+}
+
+char16_t *
+nsBeckyStringBundle::GetStringByName(const char16_t *aName)
+{
+  EnsureStringBundle();
+
+  char16_t *string = nullptr;
+  if (mBundle)
+    mBundle->GetStringFromName(aName, &string);
+
+  return string;
+}
+
+nsresult
+nsBeckyStringBundle::FormatStringFromName(const char16_t *name,
+                                          const char16_t **params,
+                                          uint32_t length,
+                                          char16_t **_retval)
+{
+  EnsureStringBundle();
+
+  return mBundle->FormatStringFromName(name,
+                                       params,
+                                       length,
+                                       _retval);
+}
+
+void
+nsBeckyStringBundle::Cleanup(void)
+{
+  if (mBundle)
+    mBundle->Release();
+  mBundle = nullptr;
+}
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyStringBundle.h
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef _nsBeckyStringBundle_H__
+#define _nsBeckyStringBundle_H__
+
+#include "nsString.h"
+
+class nsIStringBundle;
+
+class nsBeckyStringBundle final {
+public:
+  static char16_t *GetStringByName(const char16_t *name);
+  static nsresult FormatStringFromName(const char16_t *name,
+                                       const char16_t **params,
+                                       uint32_t length,
+                                       char16_t **_retval);
+  static nsIStringBundle * GetStringBundle(void); // don't release
+  static void EnsureStringBundle(void);
+  static void Cleanup(void);
+private:
+  static nsIStringBundle *mBundle;
+};
+
+#define BECKYIMPORT_NAME                     2000
+#define BECKYIMPORT_DESCRIPTION              2001
+#define BECKYIMPORT_MAILBOX_SUCCESS          2002
+#define BECKYIMPORT_MAILBOX_BADPARAM         2003
+#define BECKYIMPORT_MAILBOX_CONVERTERROR     2004
+#define BECKYIMPORT_ADDRESS_SUCCESS          2005
+
+
+#endif /* _nsBeckyStringBundle_H__ */
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyUtils.cpp
@@ -0,0 +1,315 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "nsISimpleEnumerator.h"
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsString.h"
+#include "nsIUTF8ConverterService.h"
+#include "nsUConvCID.h"
+#include "nsNativeCharsetUtils.h"
+#include "nsIInputStream.h"
+#include "nsIOutputStream.h"
+#include "nsILineInputStream.h"
+#include "nsIConverterInputStream.h"
+#include "nsIConverterOutputStream.h"
+#include "nsMsgI18N.h"
+#include "nsNetUtil.h"
+#include "nsIINIParser.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsMsgUtils.h"
+#include "msgCore.h"
+#include "nsIImportMail.h"
+#include "nsThreadUtils.h"
+
+#include "nsBeckyUtils.h"
+#include <windows.h>
+
+nsresult
+nsBeckyUtils::FindUserDirectoryOnWindows7(nsIFile **aLocation)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> directory;
+  rv = GetSpecialDirectoryWithFileName(NS_WIN_DOCUMENTS_DIR,
+                                       "Becky",
+                                       getter_AddRefs(directory));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists = false;
+  rv = directory->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  directory.forget(aLocation);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::FindUserDirectoryOnWindowsXP(nsIFile **aLocation)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIFile> directory = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = directory->InitWithPath(NS_LITERAL_STRING("C:\\Becky!"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists = false;
+  rv = directory->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more;
+  nsCOMPtr<nsISupports> entry;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&more)) && more) {
+    rv = entries->GetNext(getter_AddRefs(entry));
+
+    nsCOMPtr<nsIFile> file = do_QueryInterface(entry, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    bool isDirectory = false;
+    rv = file->IsDirectory(&isDirectory);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (isDirectory) {
+      file.forget(aLocation);
+      return NS_OK;
+    }
+  }
+
+  directory.forget(aLocation);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::FindUserDirectory(nsIFile **aLocation)
+{
+  nsresult rv = FindUserDirectoryOnWindows7(aLocation);
+  if (rv == NS_ERROR_FILE_NOT_FOUND) {
+    rv = FindUserDirectoryOnWindowsXP(aLocation);
+  }
+  return rv;
+}
+
+nsresult
+nsBeckyUtils::ConvertNativeStringToUTF8(const nsACString& aOriginal,
+                                        nsACString& _retval)
+{
+  nsresult rv;
+  nsAutoString unicodeString;
+  rv = NS_CopyNativeToUnicode(aOriginal, unicodeString);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  CopyUTF16toUTF8(unicodeString, _retval);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::CreateLineInputStream(nsIFile *aFile,
+                                    nsILineInputStream **_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsCOMPtr<nsIInputStream> inputStream;
+  nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), aFile);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return CallQueryInterface(inputStream, _retval);
+}
+
+nsresult
+nsBeckyUtils::GetFolderListFile(nsIFile *aLocation, nsIFile **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> folderListFile;
+  rv = aLocation->Clone(getter_AddRefs(folderListFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = folderListFile->Append(NS_LITERAL_STRING("Folder.lst"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists;
+  rv = folderListFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  folderListFile.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::GetDefaultFolderName(nsIFile *aFolderListFile, nsACString& name)
+{
+  nsresult rv;
+  nsCOMPtr<nsILineInputStream> lineStream;
+  rv = CreateLineInputStream(aFolderListFile, getter_AddRefs(lineStream));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool more = true;
+  rv = lineStream->ReadLine(name, &more);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::GetDefaultMailboxDirectory(nsIFile **_retval)
+{
+  nsCOMPtr<nsIFile> userDirectory;
+  nsresult rv = FindUserDirectory(getter_AddRefs(userDirectory));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIFile> folderListFile;
+  rv = GetFolderListFile(userDirectory, getter_AddRefs(folderListFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoCString defaultFolderName;
+  rv = GetDefaultFolderName(folderListFile, defaultFolderName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = userDirectory->AppendNative(defaultFolderName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists;
+  rv = userDirectory->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  userDirectory.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::GetDefaultMailboxINIFile(nsIFile **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> mailboxDirectory;
+  rv = GetDefaultMailboxDirectory(getter_AddRefs(mailboxDirectory));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return GetMailboxINIFile(mailboxDirectory, _retval);
+}
+
+nsresult
+nsBeckyUtils::GetMailboxINIFile(nsIFile *aDirectory, nsIFile **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> target;
+  rv = aDirectory->Clone(getter_AddRefs(target));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = target->Append(NS_LITERAL_STRING("Mailbox.ini"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  bool exists;
+  rv = target->Exists(&exists);
+  if (!exists)
+    return NS_ERROR_FILE_NOT_FOUND;
+
+  target.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::CreateINIParserForFile(nsIFile *aFile,
+                                     nsIINIParser **aParser)
+{
+  nsresult rv;
+  nsCOMPtr<nsIINIParserFactory> factory =
+    do_GetService("@mozilla.org/xpcom/ini-processor-factory;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return factory->CreateINIParser(aFile, aParser);
+}
+
+nsresult
+nsBeckyUtils::GetMailboxNameFromINIFile(nsIFile *aFile, nsCString &aName)
+{
+  nsresult rv;
+  nsCOMPtr<nsIINIParser> parser;
+  rv = CreateINIParserForFile(aFile, getter_AddRefs(parser));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return parser->GetString(NS_LITERAL_CSTRING("Account"),
+                           NS_LITERAL_CSTRING("Name"),
+                           aName);
+}
+
+nsresult
+nsBeckyUtils::ConvertToUTF8File(nsIFile *aSourceFile,
+                                nsIFile **_retval)
+{
+  nsresult rv;
+  nsCOMPtr<nsIFile> convertedFile;
+  rv = GetSpecialDirectoryWithFileName(NS_OS_TEMP_DIR,
+                                       "thunderbird-becky-import",
+                                       getter_AddRefs(convertedFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = convertedFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIInputStream> source;
+  rv = NS_NewLocalFileInputStream(getter_AddRefs(source), aSourceFile);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIOutputStream> destination;
+  rv = NS_NewLocalFileOutputStream(getter_AddRefs(destination),
+                                   convertedFile);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  const uint32_t kBlock = 8192;
+
+  nsCOMPtr<nsIConverterInputStream> convertedInput;
+  convertedInput->Init(source, nsMsgI18NFileSystemCharset(), kBlock, 0x0000);
+
+  nsCOMPtr<nsIConverterOutputStream> convertedOutput;
+  convertedOutput->Init(destination, "UTF-8", kBlock, 0x0000);
+
+  char16_t *line = (char16_t *)moz_xmalloc(kBlock);
+  uint32_t readBytes = kBlock;
+  bool writtenBytes;
+  while (readBytes == kBlock) {
+    rv = convertedInput->Read(line, kBlock, &readBytes);
+    rv = convertedOutput->Write(readBytes, line, &writtenBytes);
+  }
+  convertedOutput->Close();
+  convertedInput->Close();
+
+  convertedFile.forget(_retval);
+  return NS_OK;
+}
+
+nsresult
+nsBeckyUtils::TranslateFolderName(const nsAString & aFolderName,
+                                  nsAString & _retval)
+{
+  if (aFolderName.LowerCaseEqualsLiteral("!trash"))
+    _retval = NS_LITERAL_STRING(kDestTrashFolderName);
+  else if (aFolderName.LowerCaseEqualsLiteral("!!!!inbox"))
+    _retval = NS_LITERAL_STRING(kDestInboxFolderName);
+  else if (aFolderName.LowerCaseEqualsLiteral("!!!!outbox"))
+    _retval = NS_LITERAL_STRING(kDestSentFolderName);
+  else if (aFolderName.LowerCaseEqualsLiteral("!!!!unsent"))
+    _retval = NS_LITERAL_STRING(kDestUnsentMessagesFolderName);
+  else
+    _retval = aFolderName;
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/mailnews/import/becky/src/nsBeckyUtils.h
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef _nsBeckyUtils_H__
+#define _nsBeckyUtils_H__
+
+class nsIFile;
+class nsILineInputStream;
+class nsIINIParser;
+
+class nsBeckyUtils final {
+public:
+  static nsresult FindUserDirectoryOnWindows7(nsIFile **aLocation);
+  static nsresult FindUserDirectoryOnWindowsXP(nsIFile **aLocation);
+  static nsresult FindUserDirectory(nsIFile **aFile);
+  static nsresult ConvertNativeStringToUTF8(const nsACString& aOriginal,
+                                            nsACString& _retval);
+  static nsresult CreateLineInputStream(nsIFile *aFile,
+                                        nsILineInputStream **_retval);
+  static nsresult GetDefaultMailboxDirectory(nsIFile **_retval);
+  static nsresult GetFolderListFile(nsIFile *aLocation,
+                                    nsIFile **_retval);
+  static nsresult GetDefaultFolderName(nsIFile *aFolderListFile,
+                                       nsACString& name);
+  static nsresult GetDefaultMailboxINIFile(nsIFile **_retval);
+  static nsresult GetMailboxINIFile(nsIFile *aDirectory, nsIFile **_retval);
+  static nsresult CreateINIParserForFile(nsIFile *aFile,
+                                         nsIINIParser **aParser);
+  static nsresult GetMailboxNameFromINIFile(nsIFile *aFile, nsCString &aName);
+  static nsresult ConvertToUTF8File(nsIFile *aSourceFile,
+                                    nsIFile **_retval);
+  static nsresult TranslateFolderName(const nsAString & aFolderName,
+                                      nsAString & _retval);
+};
+
+
+#endif /* _nsBeckyUtils_H__ */
--- a/mailnews/import/build/moz.build
+++ b/mailnews/import/build/moz.build
@@ -43,16 +43,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
     OS_LIBS += CONFIG['TK_LIBS']
     OS_LIBS += ['-framework Cocoa']
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     LOCAL_INCLUDES += [
     ]
     if not CONFIG['GNU_CC']:
         LOCAL_INCLUDES += [
+            '../becky/src',
             '../oexpress',
             '../outlook/src',
             '../winlivemail',
         ]
     if CONFIG['MOZ_MAPI_SUPPORT']:
         LOCAL_INCLUDES += [
             '../outlook/src',
         ]
--- a/mailnews/import/build/nsImportModule.cpp
+++ b/mailnews/import/build/nsImportModule.cpp
@@ -58,16 +58,26 @@ NS_DEFINE_NAMED_CID(NS_APPLEMAILIMPL_CID
 NS_DEFINE_NAMED_CID(NS_OEIMPORT_CID);
 NS_DEFINE_NAMED_CID(NS_WMIMPORT_CID);
 #ifdef MOZ_MAPI_SUPPORT
 NS_DEFINE_NAMED_CID(NS_OUTLOOKIMPORT_CID);
 #endif
 #endif // XP_WIN
 
 ////////////////////////////////////////////////////////////////////////////////
+// becky import Include Files
+////////////////////////////////////////////////////////////////////////////////
+#ifdef XP_WIN
+#include "nsBeckyImport.h"
+#include "nsBeckyStringBundle.h"
+
+NS_DEFINE_NAMED_CID(NS_BECKYIMPORT_CID);
+#endif // XP_WIN
+
+////////////////////////////////////////////////////////////////////////////////
 // core import factories
 ////////////////////////////////////////////////////////////////////////////////
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsImportService)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsIImportMimeEncodeImpl)
 
 ////////////////////////////////////////////////////////////////////////////////
 // text import factories
 ////////////////////////////////////////////////////////////////////////////////
@@ -91,25 +101,32 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAp
 ////////////////////////////////////////////////////////////////////////////////
 #ifdef XP_WIN
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsOEImport)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWMImport)
 #ifdef MOZ_MAPI_SUPPORT
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsOutlookImport)
 #endif
 #endif // XP_WIN
+////////////////////////////////////////////////////////////////////////////////
+// becky import factory
+////////////////////////////////////////////////////////////////////////////////
+#ifdef XP_WIN
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsBeckyImport)
+#endif // XP_WIN
 
 static const mozilla::Module::CategoryEntry kMailNewsImportCategories[] = {
   // XXX These CIDs should match the explicit CIDs defined in the header files,
   // or be changed so that they are contract IDs (with appropriate code updates)
   { "mailnewsimport", "{A5991D01-ADA7-11d3-A9C2-00A0CC26DA63}", NS_IMPORT_ADDRESS_STR },
   { "mailnewsimport", "{0eb034a3-964a-4e2f-92eb-cc55d9ae9dd2}", NS_IMPORT_ADDRESS_STR },
 #ifdef XP_WIN
   { "mailnewsimport", "{42bc82bc-8e9f-4597-8b6e-e529daaf3af1}", kWMSupportsString },
   { "mailnewsimport", "{be0bc880-1742-11d3-a206-00a0cc26da63}", kOESupportsString },
+  { "mailnewsimport", "{7952a6cf-2442-4c04-9f02-150b15a0a841}", kBeckySupportsString },
 #ifdef MOZ_MAPI_SUPPORT
   { "mailnewsimport", "{1DB469A0-8B00-11d3-A206-00A0CC26DA63}", kOutlookSupportsString },
 #endif
 #endif
 #if defined(XP_MACOSX)
   { "mailnewsimport", "{6d3f101c-70ec-4e04-b68d-9908d1aeddf3}", kAppleMailSupportsString },
 #endif
   { NULL }
@@ -123,16 +140,17 @@ const mozilla::Module::CIDEntry kMailNew
 #if defined(XP_MACOSX)
   { &kNS_APPLEMAILIMPORT_CID, false, NULL, nsAppleMailImportModuleConstructor },
   { &kNS_APPLEMAILIMPL_CID, false, NULL, nsAppleMailImportMailConstructor },
 #endif
 
 #ifdef XP_WIN
   { &kNS_OEIMPORT_CID, false, NULL, nsOEImportConstructor },
   { &kNS_WMIMPORT_CID, false, NULL, nsWMImportConstructor },
+  { &kNS_BECKYIMPORT_CID, false, NULL, nsBeckyImportConstructor },
 #ifdef MOZ_MAPI_SUPPORT
   { &kNS_OUTLOOKIMPORT_CID, false, NULL, nsOutlookImportConstructor },
 #endif
 #endif
   { NULL }
 };
 
 const mozilla::Module::ContractIDEntry kMailNewsImportContracts[] = {
@@ -143,30 +161,32 @@ const mozilla::Module::ContractIDEntry k
 #if defined(XP_MACOSX)
   { "@mozilla.org/import/import-applemail;1", &kNS_APPLEMAILIMPORT_CID },
   { NS_APPLEMAILIMPL_CONTRACTID, &kNS_APPLEMAILIMPL_CID },
 #endif
 
 #ifdef XP_WIN
   { "@mozilla.org/import/import-oe;1", &kNS_OEIMPORT_CID },
   { "@mozilla.org/import/import-wm;1", &kNS_WMIMPORT_CID },
+  { "@mozilla.org/import/import-becky;1", &kNS_BECKYIMPORT_CID },
 #ifdef MOZ_MAPI_SUPPORT
   { "@mozilla.org/import/import-outlook;1", &kNS_OUTLOOKIMPORT_CID },
 #endif
 #endif
   { NULL }
 };
 
 
 static void importModuleDtor()
 {
 #ifdef XP_WIN
 
     nsOEStringBundle::Cleanup();
     nsWMStringBundle::Cleanup();
+    nsBeckyStringBundle::Cleanup();
 #ifdef MOZ_MAPI_SUPPORT
     nsOutlookStringBundle::Cleanup();
 #endif
 #endif
 }
 
 static const mozilla::Module kMailNewsImportModule = {
   mozilla::Module::kVersion,
--- a/mailnews/import/vcard/src/moz.build
+++ b/mailnews/import/vcard/src/moz.build
@@ -3,14 +3,18 @@
 # 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/.
 
 SOURCES += [
     'nsVCardAddress.cpp',
     'nsVCardImport.cpp',
 ]
 
+EXPORTS += [
+    'nsVCardAddress.h',
+]
+
 FINAL_LIBRARY = 'import'
 
 LOCAL_INCLUDES += [
     '../../src'
 ]
 
--- a/mailnews/moz.build
+++ b/mailnews/moz.build
@@ -24,16 +24,18 @@ DIRS += [
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     DIRS += [
         'import/applemail/src',
     ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
+    DIRS += [ 'import/becky/src' ]
+
     if CONFIG['MOZ_MAPI_SUPPORT']:
         DIRS += ['import/outlook/src']
 
     if not CONFIG['GNU_CC']:
         DIRS += [
             'import/oexpress',
             'import/winlivemail',
         ]