diff options
Diffstat (limited to 'mailnews/import/becky')
-rw-r--r-- | mailnews/import/becky/src/moz.build | 16 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyAddressBooks.cpp | 383 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyAddressBooks.h | 35 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyFilters.cpp | 793 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyFilters.h | 77 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyImport.cpp | 168 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyImport.h | 36 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyMail.cpp | 641 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyMail.h | 45 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckySettings.cpp | 471 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckySettings.h | 52 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyStringBundle.cpp | 74 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyStringBundle.h | 33 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyUtils.cpp | 334 | ||||
-rw-r--r-- | mailnews/import/becky/src/nsBeckyUtils.h | 37 |
15 files changed, 3195 insertions, 0 deletions
diff --git a/mailnews/import/becky/src/moz.build b/mailnews/import/becky/src/moz.build new file mode 100644 index 000000000..ce7651aa8 --- /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' diff --git a/mailnews/import/becky/src/nsBeckyAddressBooks.cpp b/mailnews/import/becky/src/nsBeckyAddressBooks.cpp new file mode 100644 index 000000000..86654ac0e --- /dev/null +++ b/mailnews/import/becky/src/nsBeckyAddressBooks.cpp @@ -0,0 +1,383 @@ +/* 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 = true; + 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(u"BeckyImportDescription"); + *_retval = false; + + return NS_OK; +} + +NS_IMETHODIMP +nsBeckyAddressBooks::GetNeedsFieldMap(nsIFile *aLocation, bool *_retval) +{ + NS_ENSURE_ARG_POINTER(_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 = false; + rv = userDirectory->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + if (!exists) + return NS_ERROR_FILE_NOT_FOUND; + + bool isDirectory = false; + rv = userDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + if (!isDirectory) + 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) +{ + if (!aFile) + return false; + + nsresult rv; + bool isFile = false; + rv = aFile->IsFile(&isFile); + if (NS_FAILED(rv) && !isFile) + return false; + + nsAutoString name; + rv = aFile->GetLeafName(name); + return StringEndsWith(name, NS_LITERAL_STRING(".bab")); +} + +bool +nsBeckyAddressBooks::HasAddressBookFile(nsIFile *aDirectory) +{ + if (!aDirectory) + return false; + + 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) +{ + if (!aDirectory) + return 0; + + 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) +{ + NS_ENSURE_ARG_POINTER(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(u"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; +} + diff --git a/mailnews/import/becky/src/nsBeckyAddressBooks.h b/mailnews/import/becky/src/nsBeckyAddressBooks.h new file mode 100644 index 000000000..83eb4c895 --- /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___ */ diff --git a/mailnews/import/becky/src/nsBeckyFilters.cpp b/mailnews/import/becky/src/nsBeckyFilters.cpp new file mode 100644 index 000000000..517a18014 --- /dev/null +++ b/mailnews/import/becky/src/nsBeckyFilters.cpp @@ -0,0 +1,793 @@ +/* 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::GetDefaultFilterLocation(nsIFile **aFile) +{ + NS_ENSURE_ARG_POINTER(aFile); + + nsresult rv; + nsCOMPtr<nsIFile> filterDir; + rv = nsBeckyUtils::GetDefaultMailboxDirectory(getter_AddRefs(filterDir)); + NS_ENSURE_SUCCESS(rv, rv); + + filterDir.forget(aFile); + return NS_OK; +} + +nsresult +nsBeckyFilters::GetFilterFile(bool aIncoming, nsIFile *aLocation, nsIFile **aFile) +{ + NS_ENSURE_ARG_POINTER(aLocation); + NS_ENSURE_ARG_POINTER(aFile); + + // We assume the caller has already checked that aLocation is a directory, + // otherwise it would not make sense to call us. + + nsresult rv; + nsCOMPtr<nsIFile> filter; + aLocation->Clone(getter_AddRefs(filter)); + if (aIncoming) + rv = filter->Append(NS_LITERAL_STRING("IFilter.def")); + else + rv = filter->Append(NS_LITERAL_STRING("OFilter.def")); + NS_ENSURE_SUCCESS(rv, rv); + + bool exists = false; + 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(aLocation); + NS_ENSURE_ARG_POINTER(_retval); + + if (aDescription) { + *aDescription = + nsBeckyStringBundle::GetStringByName(u"BeckyImportDescription"); + } + *aLocation = nullptr; + *_retval = false; + + nsresult rv; + nsCOMPtr<nsIFile> location; + rv = GetDefaultFilterLocation(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) +{ + NS_ENSURE_ARG_POINTER(aLocation); + + bool exists = false; + nsresult rv = aLocation->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + if (!exists) + return NS_ERROR_FILE_NOT_FOUND; + + 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(bool aIncoming, 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); + + if (aIncoming) + filter->SetFilterType(nsMsgFilterType::InboxRule | nsMsgFilterType::Manual); + else + filter->SetFilterType(nsMsgFilterType::PostOutgoing | nsMsgFilterType::Manual); + + 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, bool aIncoming) +{ + 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(aIncoming, 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); + + // If mLocation is null, set it to the default filter directory. + // If mLocation is a file, we import it as incoming folder. + // If mLocation is a directory, we try to import incoming and outgoing folders + // from it (in default files). + + *_retval = false; + nsresult rv; + nsCOMPtr<nsIFile> filterFile; + + bool haveFile = false; + + if (!mLocation) { + bool retval = false; + rv = AutoLocate(nullptr, getter_AddRefs(mLocation), &retval); + NS_ENSURE_SUCCESS(rv, rv); + if (!retval) + return NS_ERROR_FILE_NOT_FOUND; + } + + // What type of location do we have? + bool isDirectory = false; + rv = mLocation->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + if (isDirectory) { + haveFile = false; + } else { + bool isFile = false; + rv = mLocation->IsFile(&isFile); + NS_ENSURE_SUCCESS(rv, rv); + if (isFile) { + haveFile = true; + mLocation->Clone(getter_AddRefs(filterFile)); + } else { + // mLocation is neither file nor directory. + return NS_ERROR_UNEXPECTED; + } + } + + bool haveIncoming = true; + if (haveFile) { + // If the passed filename equals OFilter.def, import as outgoing filters. + // Everything else is considered incoming. + nsAutoString fileName; + rv = mLocation->GetLeafName(fileName); + NS_ENSURE_SUCCESS(rv, rv); + if (fileName.EqualsLiteral("OFilter.def")) + haveIncoming = false; + } + + // Try importing from the passed in file or the default incoming filters file. + if ((haveFile && haveIncoming) || (!haveFile && + NS_SUCCEEDED(GetFilterFile(true, mLocation, getter_AddRefs(filterFile))))) + { + rv = CollectServers(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = nsBeckyUtils::ConvertToUTF8File(filterFile, getter_AddRefs(mConvertedFile)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ParseFilterFile(mConvertedFile, true); + if (NS_SUCCEEDED(rv)) + *_retval = true; + + (void)RemoveConvertedFile(); + } + + // If we didn't have a file passed (but a directory), try finding also outgoing filters. + if ((haveFile && !haveIncoming) || (!haveFile && + NS_SUCCEEDED(GetFilterFile(false, mLocation, getter_AddRefs(filterFile))))) + { + rv = CollectServers(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = nsBeckyUtils::ConvertToUTF8File(filterFile, getter_AddRefs(mConvertedFile)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ParseFilterFile(mConvertedFile, false); + if (NS_SUCCEEDED(rv)) + *_retval = true; + + (void)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() +{ + nsresult rv = NS_OK; + if (mConvertedFile) { + bool exists = false; + mConvertedFile->Exists(&exists); + if (exists) { + rv = mConvertedFile->Remove(false); + if (NS_SUCCEEDED(rv)) + mConvertedFile = nullptr; + } + } + return rv; +} + diff --git a/mailnews/import/becky/src/nsBeckyFilters.h b/mailnews/import/becky/src/nsBeckyFilters.h new file mode 100644 index 000000000..20dd6d5ee --- /dev/null +++ b/mailnews/import/becky/src/nsBeckyFilters.h @@ -0,0 +1,77 @@ +/* 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 GetDefaultFilterLocation(nsIFile **aFile); + nsresult GetFilterFile(bool aIncoming, nsIFile *aLocation, nsIFile **aFile); + nsresult ParseFilterFile(nsIFile *aFile, bool aIncoming); + 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(bool aIncoming, 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___ */ diff --git a/mailnews/import/becky/src/nsBeckyImport.cpp b/mailnews/import/becky/src/nsBeckyImport.cpp new file mode 100644 index 000000000..d4820528a --- /dev/null +++ b/mailnews/import/becky/src/nsBeckyImport.cpp @@ -0,0 +1,168 @@ +/* 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 "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(u"BeckyImportName"); + return NS_OK; +} + +NS_IMETHODIMP +nsBeckyImport::GetDescription(char16_t **aDescription) +{ + NS_ENSURE_ARG_POINTER(aDescription); + *aDescription = + nsBeckyStringBundle::GetStringByName(u"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(u"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; +} diff --git a/mailnews/import/becky/src/nsBeckyImport.h b/mailnews/import/becky/src/nsBeckyImport.h new file mode 100644 index 000000000..60d81c18c --- /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___ */ diff --git a/mailnews/import/becky/src/nsBeckyMail.cpp b/mailnews/import/becky/src/nsBeckyMail.cpp new file mode 100644 index 000000000..9c837d190 --- /dev/null +++ b/mailnews/import/becky/src/nsBeckyMail.cpp @@ -0,0 +1,641 @@ +/* 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 "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 mozilla::Runnable +{ +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[FILE_IO_BUFFER_SIZE]; + 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(u"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); +} + diff --git a/mailnews/import/becky/src/nsBeckyMail.h b/mailnews/import/becky/src/nsBeckyMail.h new file mode 100644 index 000000000..ae287a05f --- /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___ */ diff --git a/mailnews/import/becky/src/nsBeckySettings.cpp b/mailnews/import/becky/src/nsBeckySettings.cpp new file mode 100644 index 000000000..8e1cab960 --- /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(u"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->SetLabel(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; +} + diff --git a/mailnews/import/becky/src/nsBeckySettings.h b/mailnews/import/becky/src/nsBeckySettings.h new file mode 100644 index 000000000..19e7d45ed --- /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___ */ diff --git a/mailnews/import/becky/src/nsBeckyStringBundle.cpp b/mailnews/import/becky/src/nsBeckyStringBundle.cpp new file mode 100644 index 000000000..41209dff5 --- /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; +} diff --git a/mailnews/import/becky/src/nsBeckyStringBundle.h b/mailnews/import/becky/src/nsBeckyStringBundle.h new file mode 100644 index 000000000..190208c9d --- /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__ */ diff --git a/mailnews/import/becky/src/nsBeckyUtils.cpp b/mailnews/import/becky/src/nsBeckyUtils.cpp new file mode 100644 index 000000000..2e9af84a5 --- /dev/null +++ b/mailnews/import/becky/src/nsBeckyUtils.cpp @@ -0,0 +1,334 @@ +/* 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" + +nsresult +nsBeckyUtils::FindUserDirectoryOnWindows7(nsIFile **aLocation) +{ + NS_ENSURE_ARG_POINTER(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; + + bool isDirectory = false; + rv = directory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + if (!isDirectory) + return NS_ERROR_FILE_NOT_FOUND; + + directory.forget(aLocation); + return NS_OK; +} + +nsresult +nsBeckyUtils::FindUserDirectoryOnWindowsXP(nsIFile **aLocation) +{ + NS_ENSURE_ARG_POINTER(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; + + bool isDirectory = false; + rv = directory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + if (!isDirectory) + 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; + + bool isDirectory = false; + rv = userDirectory->IsDirectory(&isDirectory); + NS_ENSURE_SUCCESS(rv, rv); + if (!isDirectory) + 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 = + do_CreateInstance("@mozilla.org/intl/converter-input-stream;1"); + convertedInput->Init(source, nsMsgI18NFileSystemCharset(), kBlock, 0x0000); + + nsCOMPtr<nsIConverterOutputStream> convertedOutput = + do_CreateInstance("@mozilla.org/intl/converter-output-stream;1"); + 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; +} diff --git a/mailnews/import/becky/src/nsBeckyUtils.h b/mailnews/import/becky/src/nsBeckyUtils.h new file mode 100644 index 000000000..8b6e3a542 --- /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__ */ |