summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/import/src/nsImportAddressBooks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/import/src/nsImportAddressBooks.cpp')
-rw-r--r--comm/mailnews/import/src/nsImportAddressBooks.cpp571
1 files changed, 571 insertions, 0 deletions
diff --git a/comm/mailnews/import/src/nsImportAddressBooks.cpp b/comm/mailnews/import/src/nsImportAddressBooks.cpp
new file mode 100644
index 0000000000..b39e7c68ef
--- /dev/null
+++ b/comm/mailnews/import/src/nsImportAddressBooks.cpp
@@ -0,0 +1,571 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsImportAddressBooks.h"
+
+#include "plstr.h"
+#include "nsIImportService.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIImportABDescriptor.h"
+#include "nsIAbManager.h"
+#include "nsImportStringBundle.h"
+#include "nsTextFormatter.h"
+#include "msgCore.h"
+#include "ImportDebug.h"
+
+nsresult NS_NewGenericAddressBooks(nsIImportGeneric** aImportGeneric) {
+ NS_ASSERTION(aImportGeneric != nullptr, "null ptr");
+ if (!aImportGeneric) return NS_ERROR_NULL_POINTER;
+
+ RefPtr<nsImportGenericAddressBooks> pGen = new nsImportGenericAddressBooks();
+ return pGen->QueryInterface(NS_GET_IID(nsIImportGeneric),
+ (void**)aImportGeneric);
+}
+
+nsImportGenericAddressBooks::nsImportGenericAddressBooks() {
+ m_totalSize = 0;
+ m_doImport = false;
+ m_pThreadData = nullptr;
+
+ m_autoFind = false;
+ m_description = nullptr;
+ m_gotLocation = false;
+ m_found = false;
+ m_userVerify = false;
+
+ nsImportStringBundle::GetStringBundle(IMPORT_MSGS_URL,
+ getter_AddRefs(m_stringBundle));
+}
+
+nsImportGenericAddressBooks::~nsImportGenericAddressBooks() {
+ if (m_description) free(m_description);
+}
+
+NS_IMPL_ISUPPORTS(nsImportGenericAddressBooks, nsIImportGeneric)
+
+NS_IMETHODIMP nsImportGenericAddressBooks::GetData(const char* dataId,
+ nsISupports** _retval) {
+ NS_ENSURE_ARG_POINTER(_retval);
+ nsresult rv;
+ *_retval = nullptr;
+ if (!PL_strcasecmp(dataId, "addressInterface")) {
+ NS_IF_ADDREF(*_retval = m_pInterface);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressLocation")) {
+ if (!m_pLocation) GetDefaultLocation();
+ NS_IF_ADDREF(*_retval = m_pLocation);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressDestination")) {
+ if (!m_pDestinationUri.IsEmpty()) {
+ nsCOMPtr<nsISupportsCString> abString =
+ do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ abString->SetData(m_pDestinationUri);
+ abString.forget(_retval);
+ }
+ }
+
+ if (!PL_strcasecmp(dataId, "fieldMap")) {
+ if (m_pFieldMap) {
+ NS_ADDREF(*_retval = m_pFieldMap);
+ } else {
+ if (m_pInterface && m_pLocation) {
+ bool needsIt = false;
+ m_pInterface->GetNeedsFieldMap(m_pLocation, &needsIt);
+ if (needsIt) {
+ GetDefaultFieldMap();
+ if (m_pFieldMap) {
+ NS_ADDREF(*_retval = m_pFieldMap);
+ }
+ }
+ }
+ }
+ }
+
+ if (!PL_strncasecmp(dataId, "sampleData-", 11)) {
+ // extra the record number
+ const char* pNum = dataId + 11;
+ int32_t rNum = 0;
+ while (*pNum) {
+ rNum *= 10;
+ rNum += (*pNum - '0');
+ pNum++;
+ }
+ IMPORT_LOG1("Requesting sample data #: %ld\n", (long)rNum);
+ if (m_pInterface) {
+ nsCOMPtr<nsISupportsString> data =
+ do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) return rv;
+ char16_t* pData = nullptr;
+ bool found = false;
+ rv = m_pInterface->GetSampleData(rNum, &found, &pData);
+ if (NS_FAILED(rv)) return rv;
+ if (found) {
+ data->SetData(nsDependentString(pData));
+ data.forget(_retval);
+ }
+ free(pData);
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::SetData(const char* dataId,
+ nsISupports* item) {
+ NS_ASSERTION(dataId != nullptr, "null ptr");
+ if (!dataId) return NS_ERROR_NULL_POINTER;
+
+ if (!PL_strcasecmp(dataId, "addressInterface")) {
+ m_pInterface = nullptr;
+ if (item) m_pInterface = do_QueryInterface(item);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressLocation")) {
+ m_pLocation = nullptr;
+
+ if (item) {
+ nsresult rv;
+ m_pLocation = do_QueryInterface(item, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ if (m_pInterface) m_pInterface->SetSampleLocation(m_pLocation);
+ }
+
+ if (!PL_strcasecmp(dataId, "addressDestination")) {
+ if (item) {
+ nsCOMPtr<nsISupportsCString> abString = do_QueryInterface(item);
+ if (abString) {
+ abString->GetData(m_pDestinationUri);
+ }
+ }
+ }
+
+ if (!PL_strcasecmp(dataId, "fieldMap")) {
+ m_pFieldMap = nullptr;
+ if (item) m_pFieldMap = do_QueryInterface(item);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::GetStatus(const char* statusKind,
+ int32_t* _retval) {
+ NS_ASSERTION(statusKind != nullptr, "null ptr");
+ NS_ASSERTION(_retval != nullptr, "null ptr");
+ if (!statusKind || !_retval) return NS_ERROR_NULL_POINTER;
+
+ *_retval = 0;
+
+ if (!PL_strcasecmp(statusKind, "isInstalled")) {
+ GetDefaultLocation();
+ *_retval = (int32_t)m_found;
+ }
+
+ if (!PL_strcasecmp(statusKind, "canUserSetLocation")) {
+ GetDefaultLocation();
+ *_retval = (int32_t)m_userVerify;
+ }
+
+ if (!PL_strcasecmp(statusKind, "autoFind")) {
+ GetDefaultLocation();
+ *_retval = (int32_t)m_autoFind;
+ }
+
+ if (!PL_strcasecmp(statusKind, "supportsMultiple")) {
+ bool multi = false;
+ if (m_pInterface) m_pInterface->GetSupportsMultiple(&multi);
+ *_retval = (int32_t)multi;
+ }
+
+ if (!PL_strcasecmp(statusKind, "needsFieldMap")) {
+ bool needs = false;
+ if (m_pInterface && m_pLocation)
+ m_pInterface->GetNeedsFieldMap(m_pLocation, &needs);
+ *_retval = (int32_t)needs;
+ }
+
+ return NS_OK;
+}
+
+void nsImportGenericAddressBooks::GetDefaultLocation(void) {
+ if (!m_pInterface) return;
+
+ if ((m_pLocation && m_gotLocation) || m_autoFind) return;
+
+ if (m_description) free(m_description);
+ m_description = nullptr;
+ m_pInterface->GetAutoFind(&m_description, &m_autoFind);
+ m_gotLocation = true;
+ if (m_autoFind) {
+ m_found = true;
+ m_userVerify = false;
+ return;
+ }
+
+ nsCOMPtr<nsIFile> pLoc;
+ m_pInterface->GetDefaultLocation(getter_AddRefs(pLoc), &m_found,
+ &m_userVerify);
+ if (!m_pLocation) m_pLocation = pLoc;
+}
+
+void nsImportGenericAddressBooks::GetDefaultBooks(void) {
+ if (!m_pInterface) return;
+
+ if (!m_pLocation && !m_autoFind) return;
+
+ nsresult rv = m_pInterface->FindAddressBooks(m_pLocation, m_Books);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error: FindAddressBooks failed\n");
+ }
+}
+
+void nsImportGenericAddressBooks::GetDefaultFieldMap(void) {
+ if (!m_pInterface || !m_pLocation) return;
+
+ nsresult rv;
+ nsCOMPtr<nsIImportService> impSvc(
+ do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Unable to get nsIImportService.\n");
+ return;
+ }
+
+ rv = impSvc->CreateNewFieldMap(getter_AddRefs(m_pFieldMap));
+ if (NS_FAILED(rv)) return;
+
+ int32_t sz = 0;
+ rv = m_pFieldMap->GetNumMozFields(&sz);
+ if (NS_SUCCEEDED(rv)) rv = m_pFieldMap->DefaultFieldMap(sz);
+ if (NS_SUCCEEDED(rv)) rv = m_pInterface->InitFieldMap(m_pFieldMap);
+ if (NS_FAILED(rv)) {
+ IMPORT_LOG0("*** Error: Unable to initialize field map\n");
+ m_pFieldMap = nullptr;
+ }
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::WantsProgress(bool* _retval) {
+ NS_ASSERTION(_retval != nullptr, "null ptr");
+ NS_ENSURE_ARG_POINTER(_retval);
+
+ GetDefaultLocation();
+ GetDefaultBooks();
+
+ bool result = false;
+ uint32_t totalSize = 0;
+
+ for (nsIImportABDescriptor* book : m_Books) {
+ bool doImport = false;
+ nsresult rv = book->GetImport(&doImport);
+ if (NS_SUCCEEDED(rv) && doImport) {
+ uint32_t size = 0;
+ (void)book->GetSize(&size);
+ result = true;
+ totalSize += size;
+ }
+ }
+ m_totalSize = totalSize;
+ m_doImport = result;
+
+ *_retval = result;
+
+ return NS_OK;
+}
+
+void nsImportGenericAddressBooks::SetLogs(nsString& success, nsString& error,
+ nsISupportsString* pSuccess,
+ nsISupportsString* pError) {
+ nsAutoString str;
+ if (pSuccess) {
+ pSuccess->GetData(str);
+ str.Append(success);
+ pSuccess->SetData(success);
+ }
+ if (pError) {
+ pError->GetData(str);
+ str.Append(error);
+ pError->SetData(error);
+ }
+}
+
+already_AddRefed<nsIAbDirectory> GetAddressBookFromUri(const char* pUri) {
+ if (!pUri) return nullptr;
+
+ nsCOMPtr<nsIAbManager> abManager = do_GetService("@mozilla.org/abmanager;1");
+ if (!abManager) return nullptr;
+
+ nsCOMPtr<nsIAbDirectory> directory;
+ abManager->GetDirectory(nsDependentCString(pUri), getter_AddRefs(directory));
+ if (!directory) return nullptr;
+
+ return directory.forget();
+}
+
+already_AddRefed<nsIAbDirectory> GetAddressBook(nsString name, bool makeNew) {
+ if (!makeNew) {
+ // FIXME: How do I get the list of address books and look for a
+ // specific name. Major bogosity!
+ // For now, assume we didn't find anything with that name
+ }
+
+ IMPORT_LOG0("In GetAddressBook\n");
+
+ nsresult rv;
+ nsCOMPtr<nsIAbDirectory> directory;
+ nsCOMPtr<nsIAbManager> abManager =
+ do_GetService("@mozilla.org/abmanager;1", &rv);
+ if (NS_SUCCEEDED(rv)) {
+ nsAutoCString dirPrefId;
+ rv = abManager->NewAddressBook(name, EmptyCString(),
+ nsIAbManager::JS_DIRECTORY_TYPE,
+ EmptyCString(), dirPrefId);
+ if (NS_SUCCEEDED(rv)) {
+ rv = abManager->GetDirectoryFromId(dirPrefId, getter_AddRefs(directory));
+ }
+ }
+
+ return directory.forget();
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::BeginImport(
+ nsISupportsString* successLog, nsISupportsString* errorLog, bool* _retval) {
+ NS_ASSERTION(_retval != nullptr, "null ptr");
+ if (!_retval) return NS_ERROR_NULL_POINTER;
+
+ nsString success;
+ nsString error;
+
+ if (!m_doImport) {
+ *_retval = true;
+ nsImportStringBundle::GetStringByID(IMPORT_NO_ADDRBOOKS, m_stringBundle,
+ success);
+ SetLogs(success, error, successLog, errorLog);
+ return NS_OK;
+ }
+
+ if (!m_pInterface) {
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_AB_NOTINITIALIZED,
+ m_stringBundle, error);
+ SetLogs(success, error, successLog, errorLog);
+ *_retval = false;
+ return NS_OK;
+ }
+
+ bool needsFieldMap = false;
+
+ if (NS_FAILED(m_pInterface->GetNeedsFieldMap(m_pLocation, &needsFieldMap)) ||
+ (needsFieldMap && !m_pFieldMap)) {
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_AB_NOTINITIALIZED,
+ m_stringBundle, error);
+ SetLogs(success, error, successLog, errorLog);
+ *_retval = false;
+ return NS_OK;
+ }
+
+ m_pSuccessLog = successLog;
+ m_pErrorLog = errorLog;
+
+ // create the info need to drive address book import. We're
+ // not going to create a new thread for this since address books
+ // don't tend to be large, and import is rare.
+ m_pThreadData = new AddressThreadData();
+ m_pThreadData->books = m_Books.Clone();
+ m_pThreadData->addressImport = m_pInterface;
+ m_pThreadData->fieldMap = m_pFieldMap;
+ m_pThreadData->errorLog = m_pErrorLog;
+ m_pThreadData->successLog = m_pSuccessLog;
+ m_pThreadData->pDestinationUri = m_pDestinationUri;
+
+ // Create/obtain any address books that we need here, so that we don't need
+ // to do so inside the import thread which would just proxy the create
+ // operations back to the main thread anyway.
+ nsCOMPtr<nsIAbDirectory> db;
+ if (!m_pDestinationUri.IsEmpty()) {
+ db = GetAddressBookFromUri(m_pDestinationUri.get());
+ }
+ for (nsIImportABDescriptor* book : m_Books) {
+ if (!db) {
+ nsString name;
+ book->GetPreferredName(name);
+ db = GetAddressBook(name, true);
+ }
+ m_DBs.AppendObject(db);
+ }
+ m_pThreadData->dBs = &m_DBs;
+
+ m_pThreadData->stringBundle = m_stringBundle;
+
+ nsresult rv;
+ m_pThreadData->ldifService =
+ do_GetService("@mozilla.org/addressbook/abldifservice;1", &rv);
+
+ ImportAddressThread(m_pThreadData);
+ delete m_pThreadData;
+ m_pThreadData = nullptr;
+ *_retval = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::ContinueImport(bool* _retval) {
+ NS_ASSERTION(_retval != nullptr, "null ptr");
+ if (!_retval) return NS_ERROR_NULL_POINTER;
+
+ *_retval = true;
+ if (m_pThreadData) {
+ if (m_pThreadData->fatalError) *_retval = false;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::GetProgress(int32_t* _retval) {
+ // This returns the progress from the the currently
+ // running import mail or import address book thread.
+ NS_ASSERTION(_retval != nullptr, "null ptr");
+ if (!_retval) return NS_ERROR_NULL_POINTER;
+
+ if (!m_pThreadData || !(m_pThreadData->threadAlive)) {
+ *_retval = 100;
+ return NS_OK;
+ }
+
+ uint32_t sz = 0;
+ if (m_pThreadData->currentSize && m_pInterface) {
+ if (NS_FAILED(m_pInterface->GetImportProgress(&sz))) sz = 0;
+ }
+
+ if (m_totalSize)
+ *_retval = ((m_pThreadData->currentTotal + sz) * 100) / m_totalSize;
+ else
+ *_retval = 0;
+
+ // never return less than 5 so it looks like we are doing something!
+ if (*_retval < 5) *_retval = 5;
+
+ // as long as the thread is alive don't return completely
+ // done.
+ if (*_retval > 99) *_retval = 99;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsImportGenericAddressBooks::CancelImport(void) {
+ if (m_pThreadData) {
+ m_pThreadData->abort = true;
+ m_pThreadData = nullptr;
+ }
+
+ return NS_OK;
+}
+
+AddressThreadData::AddressThreadData() {
+ fatalError = false;
+ driverAlive = true;
+ threadAlive = true;
+ abort = false;
+ currentTotal = 0;
+ currentSize = 0;
+}
+
+AddressThreadData::~AddressThreadData() {}
+
+void nsImportGenericAddressBooks::ReportError(const char16_t* pName,
+ nsString* pStream,
+ nsIStringBundle* aBundle) {
+ if (!pStream) return;
+ // load the error string
+ char16_t* pFmt =
+ nsImportStringBundle::GetStringByID(IMPORT_ERROR_GETABOOK, aBundle);
+ nsString pText;
+ nsTextFormatter::ssprintf(pText, pFmt, pName);
+ pStream->Append(pText);
+ free(pFmt);
+ pStream->AppendLiteral(MSG_LINEBREAK);
+}
+
+static void ImportAddressThread(void* stuff) {
+ IMPORT_LOG0("In Begin ImportAddressThread\n");
+
+ AddressThreadData* pData = (AddressThreadData*)stuff;
+
+ nsString success;
+ nsString error;
+
+ uint32_t count = pData->books.Length();
+ for (uint32_t i = 0; (i < count) && !(pData->abort); i++) {
+ nsIImportABDescriptor* book = pData->books[i];
+
+ uint32_t size = 0;
+ bool doImport = false;
+ nsresult rv = book->GetImport(&doImport);
+ if (NS_SUCCEEDED(rv) && doImport) rv = book->GetSize(&size);
+
+ if (NS_SUCCEEDED(rv) && size && doImport) {
+ nsString name;
+ book->GetPreferredName(name);
+
+ nsCOMPtr<nsIAbDirectory> db = pData->dBs->ObjectAt(i);
+
+ bool fatalError = false;
+ pData->currentSize = size;
+ if (db) {
+ char16_t* pSuccess = nullptr;
+ char16_t* pError = nullptr;
+
+ /*
+ if (pData->fieldMap) {
+ int32_t sz = 0;
+ int32_t mapIndex;
+ bool active;
+ pData->fieldMap->GetMapSize(&sz);
+ IMPORT_LOG1("**** Field Map Size: %d\n", (int) sz);
+ for (int32_t i = 0; i < sz; i++) {
+ pData->fieldMap->GetFieldMap(i, &mapIndex);
+ pData->fieldMap->GetFieldActive(i, &active);
+ IMPORT_LOG3("Field map #%d: index=%d, active=%d\n", (int) i, (int)
+ mapIndex, (int) active);
+ }
+ }
+ */
+
+ rv = pData->addressImport->ImportAddressBook(
+ book, db, pData->fieldMap, pData->ldifService, &pError, &pSuccess,
+ &fatalError);
+ if (NS_SUCCEEDED(rv) && pSuccess) {
+ success.Append(pSuccess);
+ free(pSuccess);
+ }
+ if (pError) {
+ error.Append(pError);
+ free(pError);
+ }
+ } else {
+ nsImportGenericAddressBooks::ReportError(name.get(), &error,
+ pData->stringBundle);
+ }
+
+ pData->currentSize = 0;
+ pData->currentTotal += size;
+
+ if (fatalError) {
+ pData->fatalError = true;
+ break;
+ }
+ }
+ }
+
+ nsImportGenericAddressBooks::SetLogs(success, error, pData->successLog,
+ pData->errorLog);
+
+ if (pData->abort || pData->fatalError) {
+ // FIXME: do what is necessary to get rid of what has been imported so far.
+ // Nothing if we went into an existing address book! Otherwise, delete
+ // the ones we created?
+ }
+}